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
This commit is contained in:
commit
bb78be8397
|
@ -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
|
||||||
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 {
|
||||||
|
|
||||||
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).
|
||||||
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 {
|
||||||
* 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,
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
/* 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 @@ store_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
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,32 +242,13 @@ out:
|
||||||
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)
|
||||||
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)
|
||||||
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
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
|
|
||||||
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 = {
|
||||||
.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)
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
17
fs/locks.c
17
fs/locks.c
|
@ -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 @@ again:
|
||||||
* 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(¤t->files->file_lock);
|
||||||
|
f = fcheck(fd);
|
||||||
|
spin_unlock(¤t->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,
|
||||||
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 @@ again:
|
||||||
* 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(¤t->files->file_lock);
|
||||||
|
f = fcheck(fd);
|
||||||
|
spin_unlock(¤t->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 *,
|
||||||
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 *);
|
||||||
|
|
Loading…
Reference in New Issue