Commit bb78be83 authored by Linus Torvalds's avatar Linus Torvalds

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] fix SMP ordering hole in fcntl_setlk()
  [PATCH] kill ->put_inode
  [PATCH] fix reservation discarding in affs
parents 31d9168d 0b2bac2f
...@@ -92,7 +92,6 @@ prototypes: ...@@ -92,7 +92,6 @@ prototypes:
void (*destroy_inode)(struct inode *); void (*destroy_inode)(struct inode *);
void (*dirty_inode) (struct inode *); void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int); int (*write_inode) (struct inode *, int);
void (*put_inode) (struct inode *);
void (*drop_inode) (struct inode *); void (*drop_inode) (struct inode *);
void (*delete_inode) (struct inode *); void (*delete_inode) (struct inode *);
void (*put_super) (struct super_block *); void (*put_super) (struct super_block *);
...@@ -115,7 +114,6 @@ alloc_inode: no no no ...@@ -115,7 +114,6 @@ alloc_inode: no no no
destroy_inode: no destroy_inode: no
dirty_inode: no (must not sleep) dirty_inode: no (must not sleep)
write_inode: no write_inode: no
put_inode: no
drop_inode: no !!!inode_lock!!! drop_inode: no !!!inode_lock!!!
delete_inode: no delete_inode: no
put_super: yes yes no put_super: yes yes no
......
...@@ -205,7 +205,6 @@ struct super_operations { ...@@ -205,7 +205,6 @@ struct super_operations {
void (*dirty_inode) (struct inode *); void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int); int (*write_inode) (struct inode *, int);
void (*put_inode) (struct inode *);
void (*drop_inode) (struct inode *); void (*drop_inode) (struct inode *);
void (*delete_inode) (struct inode *); void (*delete_inode) (struct inode *);
void (*put_super) (struct super_block *); void (*put_super) (struct super_block *);
...@@ -246,9 +245,6 @@ or bottom half). ...@@ -246,9 +245,6 @@ or bottom half).
inode to disc. The second parameter indicates whether the write inode to disc. The second parameter indicates whether the write
should be synchronous or not, not all filesystems check this flag. should be synchronous or not, not all filesystems check this flag.
put_inode: called when the VFS inode is removed from the inode
cache.
drop_inode: called when the last access to the inode is dropped, drop_inode: called when the last access to the inode is dropped,
with the inode_lock spinlock held. with the inode_lock spinlock held.
......
...@@ -48,7 +48,7 @@ struct affs_ext_key { ...@@ -48,7 +48,7 @@ struct affs_ext_key {
* affs fs inode data in memory * affs fs inode data in memory
*/ */
struct affs_inode_info { struct affs_inode_info {
u32 i_opencnt; atomic_t i_opencnt;
struct semaphore i_link_lock; /* Protects internal inode access. */ struct semaphore i_link_lock; /* Protects internal inode access. */
struct semaphore i_ext_lock; /* Protects internal inode access. */ struct semaphore i_ext_lock; /* Protects internal inode access. */
#define i_hash_lock i_ext_lock #define i_hash_lock i_ext_lock
...@@ -170,8 +170,6 @@ extern int affs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -170,8 +170,6 @@ extern int affs_rename(struct inode *old_dir, struct dentry *old_dentry,
extern unsigned long affs_parent_ino(struct inode *dir); extern unsigned long affs_parent_ino(struct inode *dir);
extern struct inode *affs_new_inode(struct inode *dir); extern struct inode *affs_new_inode(struct inode *dir);
extern int affs_notify_change(struct dentry *dentry, struct iattr *attr); extern int affs_notify_change(struct dentry *dentry, struct iattr *attr);
extern void affs_put_inode(struct inode *inode);
extern void affs_drop_inode(struct inode *inode);
extern void affs_delete_inode(struct inode *inode); extern void affs_delete_inode(struct inode *inode);
extern void affs_clear_inode(struct inode *inode); extern void affs_clear_inode(struct inode *inode);
extern struct inode *affs_iget(struct super_block *sb, extern struct inode *affs_iget(struct super_block *sb,
......
...@@ -48,8 +48,9 @@ affs_file_open(struct inode *inode, struct file *filp) ...@@ -48,8 +48,9 @@ affs_file_open(struct inode *inode, struct file *filp)
{ {
if (atomic_read(&filp->f_count) != 1) if (atomic_read(&filp->f_count) != 1)
return 0; return 0;
pr_debug("AFFS: open(%d)\n", AFFS_I(inode)->i_opencnt); pr_debug("AFFS: open(%lu,%d)\n",
AFFS_I(inode)->i_opencnt++; inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt));
atomic_inc(&AFFS_I(inode)->i_opencnt);
return 0; return 0;
} }
...@@ -58,10 +59,16 @@ affs_file_release(struct inode *inode, struct file *filp) ...@@ -58,10 +59,16 @@ affs_file_release(struct inode *inode, struct file *filp)
{ {
if (atomic_read(&filp->f_count) != 0) if (atomic_read(&filp->f_count) != 0)
return 0; return 0;
pr_debug("AFFS: release(%d)\n", AFFS_I(inode)->i_opencnt); pr_debug("AFFS: release(%lu, %d)\n",
AFFS_I(inode)->i_opencnt--; inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt));
if (!AFFS_I(inode)->i_opencnt)
if (atomic_dec_and_test(&AFFS_I(inode)->i_opencnt)) {
mutex_lock(&inode->i_mutex);
if (inode->i_size != AFFS_I(inode)->mmu_private)
affs_truncate(inode);
affs_free_prealloc(inode); affs_free_prealloc(inode);
mutex_unlock(&inode->i_mutex);
}
return 0; return 0;
} }
...@@ -180,7 +187,7 @@ affs_get_extblock(struct inode *inode, u32 ext) ...@@ -180,7 +187,7 @@ affs_get_extblock(struct inode *inode, u32 ext)
/* inline the simplest case: same extended block as last time */ /* inline the simplest case: same extended block as last time */
struct buffer_head *bh = AFFS_I(inode)->i_ext_bh; struct buffer_head *bh = AFFS_I(inode)->i_ext_bh;
if (ext == AFFS_I(inode)->i_ext_last) if (ext == AFFS_I(inode)->i_ext_last)
atomic_inc(&bh->b_count); get_bh(bh);
else else
/* we have to do more (not inlined) */ /* we have to do more (not inlined) */
bh = affs_get_extblock_slow(inode, ext); bh = affs_get_extblock_slow(inode, ext);
...@@ -306,7 +313,7 @@ affs_get_extblock_slow(struct inode *inode, u32 ext) ...@@ -306,7 +313,7 @@ affs_get_extblock_slow(struct inode *inode, u32 ext)
affs_brelse(AFFS_I(inode)->i_ext_bh); affs_brelse(AFFS_I(inode)->i_ext_bh);
AFFS_I(inode)->i_ext_last = ext; AFFS_I(inode)->i_ext_last = ext;
AFFS_I(inode)->i_ext_bh = bh; AFFS_I(inode)->i_ext_bh = bh;
atomic_inc(&bh->b_count); get_bh(bh);
return bh; return bh;
...@@ -324,7 +331,6 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul ...@@ -324,7 +331,6 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul
pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block); pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block);
BUG_ON(block > (sector_t)0x7fffffffUL); BUG_ON(block > (sector_t)0x7fffffffUL);
if (block >= AFFS_I(inode)->i_blkcnt) { if (block >= AFFS_I(inode)->i_blkcnt) {
...@@ -827,6 +833,8 @@ affs_truncate(struct inode *inode) ...@@ -827,6 +833,8 @@ affs_truncate(struct inode *inode)
res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata); res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata);
if (!res) if (!res)
res = mapping->a_ops->write_end(NULL, mapping, size, 0, 0, page, fsdata); res = mapping->a_ops->write_end(NULL, mapping, size, 0, 0, page, fsdata);
else
inode->i_size = AFFS_I(inode)->mmu_private;
mark_inode_dirty(inode); mark_inode_dirty(inode);
return; return;
} else if (inode->i_size == AFFS_I(inode)->mmu_private) } else if (inode->i_size == AFFS_I(inode)->mmu_private)
...@@ -862,6 +870,7 @@ affs_truncate(struct inode *inode) ...@@ -862,6 +870,7 @@ affs_truncate(struct inode *inode)
blk++; blk++;
} else } else
AFFS_HEAD(ext_bh)->first_data = 0; AFFS_HEAD(ext_bh)->first_data = 0;
AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(i);
size = AFFS_SB(sb)->s_hashsize; size = AFFS_SB(sb)->s_hashsize;
if (size > blkcnt - blk + i) if (size > blkcnt - blk + i)
size = blkcnt - blk + i; size = blkcnt - blk + i;
......
...@@ -58,7 +58,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino) ...@@ -58,7 +58,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
AFFS_I(inode)->i_extcnt = 1; AFFS_I(inode)->i_extcnt = 1;
AFFS_I(inode)->i_ext_last = ~1; AFFS_I(inode)->i_ext_last = ~1;
AFFS_I(inode)->i_protect = prot; AFFS_I(inode)->i_protect = prot;
AFFS_I(inode)->i_opencnt = 0; atomic_set(&AFFS_I(inode)->i_opencnt, 0);
AFFS_I(inode)->i_blkcnt = 0; AFFS_I(inode)->i_blkcnt = 0;
AFFS_I(inode)->i_lc = NULL; AFFS_I(inode)->i_lc = NULL;
AFFS_I(inode)->i_lc_size = 0; AFFS_I(inode)->i_lc_size = 0;
...@@ -108,8 +108,6 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino) ...@@ -108,8 +108,6 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
inode->i_mode |= S_IFDIR; inode->i_mode |= S_IFDIR;
} else } else
inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR; inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR;
if (tail->link_chain)
inode->i_nlink = 2;
/* Maybe it should be controlled by mount parameter? */ /* Maybe it should be controlled by mount parameter? */
//inode->i_mode |= S_ISVTX; //inode->i_mode |= S_ISVTX;
inode->i_op = &affs_dir_inode_operations; inode->i_op = &affs_dir_inode_operations;
...@@ -244,31 +242,12 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr) ...@@ -244,31 +242,12 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)
return error; return error;
} }
void
affs_put_inode(struct inode *inode)
{
pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
affs_free_prealloc(inode);
}
void
affs_drop_inode(struct inode *inode)
{
mutex_lock(&inode->i_mutex);
if (inode->i_size != AFFS_I(inode)->mmu_private)
affs_truncate(inode);
mutex_unlock(&inode->i_mutex);
generic_drop_inode(inode);
}
void void
affs_delete_inode(struct inode *inode) affs_delete_inode(struct inode *inode)
{ {
pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
truncate_inode_pages(&inode->i_data, 0); truncate_inode_pages(&inode->i_data, 0);
inode->i_size = 0; inode->i_size = 0;
if (S_ISREG(inode->i_mode))
affs_truncate(inode); affs_truncate(inode);
clear_inode(inode); clear_inode(inode);
affs_free_block(inode->i_sb, inode->i_ino); affs_free_block(inode->i_sb, inode->i_ino);
...@@ -277,9 +256,12 @@ affs_delete_inode(struct inode *inode) ...@@ -277,9 +256,12 @@ affs_delete_inode(struct inode *inode)
void void
affs_clear_inode(struct inode *inode) affs_clear_inode(struct inode *inode)
{ {
unsigned long cache_page = (unsigned long) AFFS_I(inode)->i_lc; unsigned long cache_page;
pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
affs_free_prealloc(inode);
cache_page = (unsigned long)AFFS_I(inode)->i_lc;
if (cache_page) { if (cache_page) {
pr_debug("AFFS: freeing ext cache\n"); pr_debug("AFFS: freeing ext cache\n");
AFFS_I(inode)->i_lc = NULL; AFFS_I(inode)->i_lc = NULL;
...@@ -316,7 +298,7 @@ affs_new_inode(struct inode *dir) ...@@ -316,7 +298,7 @@ affs_new_inode(struct inode *dir)
inode->i_ino = block; inode->i_ino = block;
inode->i_nlink = 1; inode->i_nlink = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
AFFS_I(inode)->i_opencnt = 0; atomic_set(&AFFS_I(inode)->i_opencnt, 0);
AFFS_I(inode)->i_blkcnt = 0; AFFS_I(inode)->i_blkcnt = 0;
AFFS_I(inode)->i_lc = NULL; AFFS_I(inode)->i_lc = NULL;
AFFS_I(inode)->i_lc_size = 0; AFFS_I(inode)->i_lc_size = 0;
...@@ -369,12 +351,12 @@ affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s3 ...@@ -369,12 +351,12 @@ affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s3
switch (type) { switch (type) {
case ST_LINKFILE: case ST_LINKFILE:
case ST_LINKDIR: case ST_LINKDIR:
inode_bh = bh;
retval = -ENOSPC; retval = -ENOSPC;
block = affs_alloc_block(dir, dir->i_ino); block = affs_alloc_block(dir, dir->i_ino);
if (!block) if (!block)
goto err; goto err;
retval = -EIO; retval = -EIO;
inode_bh = bh;
bh = affs_getzeroblk(sb, block); bh = affs_getzeroblk(sb, block);
if (!bh) if (!bh)
goto err; goto err;
......
...@@ -234,7 +234,8 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) ...@@ -234,7 +234,8 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
int int
affs_unlink(struct inode *dir, struct dentry *dentry) affs_unlink(struct inode *dir, struct dentry *dentry)
{ {
pr_debug("AFFS: unlink(dir=%d, \"%.*s\")\n", (u32)dir->i_ino, pr_debug("AFFS: unlink(dir=%d, %lu \"%.*s\")\n", (u32)dir->i_ino,
dentry->d_inode->i_ino,
(int)dentry->d_name.len, dentry->d_name.name); (int)dentry->d_name.len, dentry->d_name.name);
return affs_remove_header(dentry); return affs_remove_header(dentry);
...@@ -302,7 +303,8 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode) ...@@ -302,7 +303,8 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
int int
affs_rmdir(struct inode *dir, struct dentry *dentry) affs_rmdir(struct inode *dir, struct dentry *dentry)
{ {
pr_debug("AFFS: rmdir(dir=%u, \"%.*s\")\n", (u32)dir->i_ino, pr_debug("AFFS: rmdir(dir=%u, %lu \"%.*s\")\n", (u32)dir->i_ino,
dentry->d_inode->i_ino,
(int)dentry->d_name.len, dentry->d_name.name); (int)dentry->d_name.len, dentry->d_name.name);
return affs_remove_header(dentry); return affs_remove_header(dentry);
......
...@@ -71,12 +71,18 @@ static struct kmem_cache * affs_inode_cachep; ...@@ -71,12 +71,18 @@ static struct kmem_cache * affs_inode_cachep;
static struct inode *affs_alloc_inode(struct super_block *sb) static struct inode *affs_alloc_inode(struct super_block *sb)
{ {
struct affs_inode_info *ei; struct affs_inode_info *i;
ei = (struct affs_inode_info *)kmem_cache_alloc(affs_inode_cachep, GFP_KERNEL);
if (!ei) i = kmem_cache_alloc(affs_inode_cachep, GFP_KERNEL);
if (!i)
return NULL; return NULL;
ei->vfs_inode.i_version = 1;
return &ei->vfs_inode; i->vfs_inode.i_version = 1;
i->i_lc = NULL;
i->i_ext_bh = NULL;
i->i_pa_cnt = 0;
return &i->vfs_inode;
} }
static void affs_destroy_inode(struct inode *inode) static void affs_destroy_inode(struct inode *inode)
...@@ -114,8 +120,6 @@ static const struct super_operations affs_sops = { ...@@ -114,8 +120,6 @@ static const struct super_operations affs_sops = {
.alloc_inode = affs_alloc_inode, .alloc_inode = affs_alloc_inode,
.destroy_inode = affs_destroy_inode, .destroy_inode = affs_destroy_inode,
.write_inode = affs_write_inode, .write_inode = affs_write_inode,
.put_inode = affs_put_inode,
.drop_inode = affs_drop_inode,
.delete_inode = affs_delete_inode, .delete_inode = affs_delete_inode,
.clear_inode = affs_clear_inode, .clear_inode = affs_clear_inode,
.put_super = affs_put_super, .put_super = affs_put_super,
......
...@@ -1153,9 +1153,6 @@ void iput(struct inode *inode) ...@@ -1153,9 +1153,6 @@ void iput(struct inode *inode)
BUG_ON(inode->i_state == I_CLEAR); BUG_ON(inode->i_state == I_CLEAR);
if (op && op->put_inode)
op->put_inode(inode);
if (atomic_dec_and_lock(&inode->i_count, &inode_lock)) if (atomic_dec_and_lock(&inode->i_count, &inode_lock))
iput_final(inode); iput_final(inode);
} }
......
...@@ -1753,6 +1753,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -1753,6 +1753,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
struct file_lock *file_lock = locks_alloc_lock(); struct file_lock *file_lock = locks_alloc_lock();
struct flock flock; struct flock flock;
struct inode *inode; struct inode *inode;
struct file *f;
int error; int error;
if (file_lock == NULL) if (file_lock == NULL)
...@@ -1825,7 +1826,15 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -1825,7 +1826,15 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
* Attempt to detect a close/fcntl race and recover by * Attempt to detect a close/fcntl race and recover by
* releasing the lock that was just acquired. * releasing the lock that was just acquired.
*/ */
if (!error && fcheck(fd) != filp && flock.l_type != F_UNLCK) { /*
* we need that spin_lock here - it prevents reordering between
* update of inode->i_flock and check for it done in close().
* rcu_read_lock() wouldn't do.
*/
spin_lock(&current->files->file_lock);
f = fcheck(fd);
spin_unlock(&current->files->file_lock);
if (!error && f != filp && flock.l_type != F_UNLCK) {
flock.l_type = F_UNLCK; flock.l_type = F_UNLCK;
goto again; goto again;
} }
...@@ -1881,6 +1890,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -1881,6 +1890,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
struct file_lock *file_lock = locks_alloc_lock(); struct file_lock *file_lock = locks_alloc_lock();
struct flock64 flock; struct flock64 flock;
struct inode *inode; struct inode *inode;
struct file *f;
int error; int error;
if (file_lock == NULL) if (file_lock == NULL)
...@@ -1953,7 +1963,10 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, ...@@ -1953,7 +1963,10 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
* Attempt to detect a close/fcntl race and recover by * Attempt to detect a close/fcntl race and recover by
* releasing the lock that was just acquired. * releasing the lock that was just acquired.
*/ */
if (!error && fcheck(fd) != filp && flock.l_type != F_UNLCK) { spin_lock(&current->files->file_lock);
f = fcheck(fd);
spin_unlock(&current->files->file_lock);
if (!error && f != filp && flock.l_type != F_UNLCK) {
flock.l_type = F_UNLCK; flock.l_type = F_UNLCK;
goto again; goto again;
} }
......
...@@ -1289,17 +1289,12 @@ extern ssize_t vfs_readv(struct file *, const struct iovec __user *, ...@@ -1289,17 +1289,12 @@ extern ssize_t vfs_readv(struct file *, const struct iovec __user *,
extern ssize_t vfs_writev(struct file *, const struct iovec __user *, extern ssize_t vfs_writev(struct file *, const struct iovec __user *,
unsigned long, loff_t *); unsigned long, loff_t *);
/*
* NOTE: write_inode, delete_inode, clear_inode, put_inode can be called
* without the big kernel lock held in all filesystems.
*/
struct super_operations { struct super_operations {
struct inode *(*alloc_inode)(struct super_block *sb); struct inode *(*alloc_inode)(struct super_block *sb);
void (*destroy_inode)(struct inode *); void (*destroy_inode)(struct inode *);
void (*dirty_inode) (struct inode *); void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int); int (*write_inode) (struct inode *, int);
void (*put_inode) (struct inode *);
void (*drop_inode) (struct inode *); void (*drop_inode) (struct inode *);
void (*delete_inode) (struct inode *); void (*delete_inode) (struct inode *);
void (*put_super) (struct super_block *); void (*put_super) (struct super_block *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment