diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-05-06 14:39:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-05-06 14:39:57 -0400 |
commit | bb78be8397d3b0900af3d717672218ee3ea07985 (patch) | |
tree | 8d16cb48aa31d29a0e3f5aa94d4b5ea965b553ba | |
parent | 31d9168d27fac127d449cb9fa252d880de872c7f (diff) | |
parent | 0b2bac2f1ea0d33a3621b27ca68b9ae760fca2e9 (diff) |
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
-rw-r--r-- | Documentation/filesystems/Locking | 2 | ||||
-rw-r--r-- | Documentation/filesystems/vfs.txt | 4 | ||||
-rw-r--r-- | fs/affs/affs.h | 4 | ||||
-rw-r--r-- | fs/affs/file.c | 25 | ||||
-rw-r--r-- | fs/affs/inode.c | 34 | ||||
-rw-r--r-- | fs/affs/namei.c | 6 | ||||
-rw-r--r-- | fs/affs/super.c | 18 | ||||
-rw-r--r-- | fs/inode.c | 3 | ||||
-rw-r--r-- | fs/locks.c | 17 | ||||
-rw-r--r-- | include/linux/fs.h | 5 |
10 files changed, 56 insertions, 62 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index c2992bc54f2f..8b22d7d8b991 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking | |||
@@ -92,7 +92,6 @@ prototypes: | |||
92 | void (*destroy_inode)(struct inode *); | 92 | void (*destroy_inode)(struct inode *); |
93 | void (*dirty_inode) (struct inode *); | 93 | void (*dirty_inode) (struct inode *); |
94 | int (*write_inode) (struct inode *, int); | 94 | int (*write_inode) (struct inode *, int); |
95 | void (*put_inode) (struct inode *); | ||
96 | void (*drop_inode) (struct inode *); | 95 | void (*drop_inode) (struct inode *); |
97 | void (*delete_inode) (struct inode *); | 96 | void (*delete_inode) (struct inode *); |
98 | void (*put_super) (struct super_block *); | 97 | void (*put_super) (struct super_block *); |
@@ -115,7 +114,6 @@ alloc_inode: no no no | |||
115 | destroy_inode: no | 114 | destroy_inode: no |
116 | dirty_inode: no (must not sleep) | 115 | dirty_inode: no (must not sleep) |
117 | write_inode: no | 116 | write_inode: no |
118 | put_inode: no | ||
119 | drop_inode: no !!!inode_lock!!! | 117 | drop_inode: no !!!inode_lock!!! |
120 | delete_inode: no | 118 | delete_inode: no |
121 | put_super: yes yes no | 119 | put_super: yes yes no |
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 81e5be6e6e35..b7522c6cbae3 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt | |||
@@ -205,7 +205,6 @@ struct super_operations { | |||
205 | 205 | ||
206 | void (*dirty_inode) (struct inode *); | 206 | void (*dirty_inode) (struct inode *); |
207 | int (*write_inode) (struct inode *, int); | 207 | int (*write_inode) (struct inode *, int); |
208 | void (*put_inode) (struct inode *); | ||
209 | void (*drop_inode) (struct inode *); | 208 | void (*drop_inode) (struct inode *); |
210 | void (*delete_inode) (struct inode *); | 209 | void (*delete_inode) (struct inode *); |
211 | void (*put_super) (struct super_block *); | 210 | void (*put_super) (struct super_block *); |
@@ -246,9 +245,6 @@ or bottom half). | |||
246 | inode to disc. The second parameter indicates whether the write | 245 | inode to disc. The second parameter indicates whether the write |
247 | should be synchronous or not, not all filesystems check this flag. | 246 | should be synchronous or not, not all filesystems check this flag. |
248 | 247 | ||
249 | put_inode: called when the VFS inode is removed from the inode | ||
250 | cache. | ||
251 | |||
252 | drop_inode: called when the last access to the inode is dropped, | 248 | drop_inode: called when the last access to the inode is dropped, |
253 | with the inode_lock spinlock held. | 249 | with the inode_lock spinlock held. |
254 | 250 | ||
diff --git a/fs/affs/affs.h b/fs/affs/affs.h index d5bd497ab9cb..223b1917093e 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h | |||
@@ -48,7 +48,7 @@ struct affs_ext_key { | |||
48 | * affs fs inode data in memory | 48 | * affs fs inode data in memory |
49 | */ | 49 | */ |
50 | struct affs_inode_info { | 50 | struct affs_inode_info { |
51 | u32 i_opencnt; | 51 | atomic_t i_opencnt; |
52 | struct semaphore i_link_lock; /* Protects internal inode access. */ | 52 | struct semaphore i_link_lock; /* Protects internal inode access. */ |
53 | struct semaphore i_ext_lock; /* Protects internal inode access. */ | 53 | struct semaphore i_ext_lock; /* Protects internal inode access. */ |
54 | #define i_hash_lock i_ext_lock | 54 | #define i_hash_lock i_ext_lock |
@@ -170,8 +170,6 @@ extern int affs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
170 | extern unsigned long affs_parent_ino(struct inode *dir); | 170 | extern unsigned long affs_parent_ino(struct inode *dir); |
171 | extern struct inode *affs_new_inode(struct inode *dir); | 171 | extern struct inode *affs_new_inode(struct inode *dir); |
172 | extern int affs_notify_change(struct dentry *dentry, struct iattr *attr); | 172 | extern int affs_notify_change(struct dentry *dentry, struct iattr *attr); |
173 | extern void affs_put_inode(struct inode *inode); | ||
174 | extern void affs_drop_inode(struct inode *inode); | ||
175 | extern void affs_delete_inode(struct inode *inode); | 173 | extern void affs_delete_inode(struct inode *inode); |
176 | extern void affs_clear_inode(struct inode *inode); | 174 | extern void affs_clear_inode(struct inode *inode); |
177 | extern struct inode *affs_iget(struct super_block *sb, | 175 | extern struct inode *affs_iget(struct super_block *sb, |
diff --git a/fs/affs/file.c b/fs/affs/file.c index 1a4f092f24ef..6eac7bdeec94 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c | |||
@@ -48,8 +48,9 @@ affs_file_open(struct inode *inode, struct file *filp) | |||
48 | { | 48 | { |
49 | if (atomic_read(&filp->f_count) != 1) | 49 | if (atomic_read(&filp->f_count) != 1) |
50 | return 0; | 50 | return 0; |
51 | pr_debug("AFFS: open(%d)\n", AFFS_I(inode)->i_opencnt); | 51 | pr_debug("AFFS: open(%lu,%d)\n", |
52 | AFFS_I(inode)->i_opencnt++; | 52 | inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt)); |
53 | atomic_inc(&AFFS_I(inode)->i_opencnt); | ||
53 | return 0; | 54 | return 0; |
54 | } | 55 | } |
55 | 56 | ||
@@ -58,10 +59,16 @@ affs_file_release(struct inode *inode, struct file *filp) | |||
58 | { | 59 | { |
59 | if (atomic_read(&filp->f_count) != 0) | 60 | if (atomic_read(&filp->f_count) != 0) |
60 | return 0; | 61 | return 0; |
61 | pr_debug("AFFS: release(%d)\n", AFFS_I(inode)->i_opencnt); | 62 | pr_debug("AFFS: release(%lu, %d)\n", |
62 | AFFS_I(inode)->i_opencnt--; | 63 | inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt)); |
63 | if (!AFFS_I(inode)->i_opencnt) | 64 | |
65 | if (atomic_dec_and_test(&AFFS_I(inode)->i_opencnt)) { | ||
66 | mutex_lock(&inode->i_mutex); | ||
67 | if (inode->i_size != AFFS_I(inode)->mmu_private) | ||
68 | affs_truncate(inode); | ||
64 | affs_free_prealloc(inode); | 69 | affs_free_prealloc(inode); |
70 | mutex_unlock(&inode->i_mutex); | ||
71 | } | ||
65 | 72 | ||
66 | return 0; | 73 | return 0; |
67 | } | 74 | } |
@@ -180,7 +187,7 @@ affs_get_extblock(struct inode *inode, u32 ext) | |||
180 | /* inline the simplest case: same extended block as last time */ | 187 | /* inline the simplest case: same extended block as last time */ |
181 | struct buffer_head *bh = AFFS_I(inode)->i_ext_bh; | 188 | struct buffer_head *bh = AFFS_I(inode)->i_ext_bh; |
182 | if (ext == AFFS_I(inode)->i_ext_last) | 189 | if (ext == AFFS_I(inode)->i_ext_last) |
183 | atomic_inc(&bh->b_count); | 190 | get_bh(bh); |
184 | else | 191 | else |
185 | /* we have to do more (not inlined) */ | 192 | /* we have to do more (not inlined) */ |
186 | bh = affs_get_extblock_slow(inode, ext); | 193 | bh = affs_get_extblock_slow(inode, ext); |
@@ -306,7 +313,7 @@ store_ext: | |||
306 | affs_brelse(AFFS_I(inode)->i_ext_bh); | 313 | affs_brelse(AFFS_I(inode)->i_ext_bh); |
307 | AFFS_I(inode)->i_ext_last = ext; | 314 | AFFS_I(inode)->i_ext_last = ext; |
308 | AFFS_I(inode)->i_ext_bh = bh; | 315 | AFFS_I(inode)->i_ext_bh = bh; |
309 | atomic_inc(&bh->b_count); | 316 | get_bh(bh); |
310 | 317 | ||
311 | return bh; | 318 | return bh; |
312 | 319 | ||
@@ -324,7 +331,6 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul | |||
324 | 331 | ||
325 | pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block); | 332 | pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block); |
326 | 333 | ||
327 | |||
328 | BUG_ON(block > (sector_t)0x7fffffffUL); | 334 | BUG_ON(block > (sector_t)0x7fffffffUL); |
329 | 335 | ||
330 | if (block >= AFFS_I(inode)->i_blkcnt) { | 336 | if (block >= AFFS_I(inode)->i_blkcnt) { |
@@ -827,6 +833,8 @@ affs_truncate(struct inode *inode) | |||
827 | res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata); | 833 | res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata); |
828 | if (!res) | 834 | if (!res) |
829 | res = mapping->a_ops->write_end(NULL, mapping, size, 0, 0, page, fsdata); | 835 | res = mapping->a_ops->write_end(NULL, mapping, size, 0, 0, page, fsdata); |
836 | else | ||
837 | inode->i_size = AFFS_I(inode)->mmu_private; | ||
830 | mark_inode_dirty(inode); | 838 | mark_inode_dirty(inode); |
831 | return; | 839 | return; |
832 | } else if (inode->i_size == AFFS_I(inode)->mmu_private) | 840 | } else if (inode->i_size == AFFS_I(inode)->mmu_private) |
@@ -862,6 +870,7 @@ affs_truncate(struct inode *inode) | |||
862 | blk++; | 870 | blk++; |
863 | } else | 871 | } else |
864 | AFFS_HEAD(ext_bh)->first_data = 0; | 872 | AFFS_HEAD(ext_bh)->first_data = 0; |
873 | AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(i); | ||
865 | size = AFFS_SB(sb)->s_hashsize; | 874 | size = AFFS_SB(sb)->s_hashsize; |
866 | if (size > blkcnt - blk + i) | 875 | if (size > blkcnt - blk + i) |
867 | size = blkcnt - blk + i; | 876 | size = blkcnt - blk + i; |
diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 27fe6cbe43ae..a13b334a3910 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c | |||
@@ -58,7 +58,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino) | |||
58 | AFFS_I(inode)->i_extcnt = 1; | 58 | AFFS_I(inode)->i_extcnt = 1; |
59 | AFFS_I(inode)->i_ext_last = ~1; | 59 | AFFS_I(inode)->i_ext_last = ~1; |
60 | AFFS_I(inode)->i_protect = prot; | 60 | AFFS_I(inode)->i_protect = prot; |
61 | AFFS_I(inode)->i_opencnt = 0; | 61 | atomic_set(&AFFS_I(inode)->i_opencnt, 0); |
62 | AFFS_I(inode)->i_blkcnt = 0; | 62 | AFFS_I(inode)->i_blkcnt = 0; |
63 | AFFS_I(inode)->i_lc = NULL; | 63 | AFFS_I(inode)->i_lc = NULL; |
64 | AFFS_I(inode)->i_lc_size = 0; | 64 | AFFS_I(inode)->i_lc_size = 0; |
@@ -108,8 +108,6 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino) | |||
108 | inode->i_mode |= S_IFDIR; | 108 | inode->i_mode |= S_IFDIR; |
109 | } else | 109 | } else |
110 | inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR; | 110 | inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR; |
111 | if (tail->link_chain) | ||
112 | inode->i_nlink = 2; | ||
113 | /* Maybe it should be controlled by mount parameter? */ | 111 | /* Maybe it should be controlled by mount parameter? */ |
114 | //inode->i_mode |= S_ISVTX; | 112 | //inode->i_mode |= S_ISVTX; |
115 | inode->i_op = &affs_dir_inode_operations; | 113 | inode->i_op = &affs_dir_inode_operations; |
@@ -245,31 +243,12 @@ out: | |||
245 | } | 243 | } |
246 | 244 | ||
247 | void | 245 | void |
248 | affs_put_inode(struct inode *inode) | ||
249 | { | ||
250 | pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); | ||
251 | affs_free_prealloc(inode); | ||
252 | } | ||
253 | |||
254 | void | ||
255 | affs_drop_inode(struct inode *inode) | ||
256 | { | ||
257 | mutex_lock(&inode->i_mutex); | ||
258 | if (inode->i_size != AFFS_I(inode)->mmu_private) | ||
259 | affs_truncate(inode); | ||
260 | mutex_unlock(&inode->i_mutex); | ||
261 | |||
262 | generic_drop_inode(inode); | ||
263 | } | ||
264 | |||
265 | void | ||
266 | affs_delete_inode(struct inode *inode) | 246 | affs_delete_inode(struct inode *inode) |
267 | { | 247 | { |
268 | pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); | 248 | pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); |
269 | truncate_inode_pages(&inode->i_data, 0); | 249 | truncate_inode_pages(&inode->i_data, 0); |
270 | inode->i_size = 0; | 250 | inode->i_size = 0; |
271 | if (S_ISREG(inode->i_mode)) | 251 | affs_truncate(inode); |
272 | affs_truncate(inode); | ||
273 | clear_inode(inode); | 252 | clear_inode(inode); |
274 | affs_free_block(inode->i_sb, inode->i_ino); | 253 | affs_free_block(inode->i_sb, inode->i_ino); |
275 | } | 254 | } |
@@ -277,9 +256,12 @@ affs_delete_inode(struct inode *inode) | |||
277 | void | 256 | void |
278 | affs_clear_inode(struct inode *inode) | 257 | affs_clear_inode(struct inode *inode) |
279 | { | 258 | { |
280 | unsigned long cache_page = (unsigned long) AFFS_I(inode)->i_lc; | 259 | unsigned long cache_page; |
281 | 260 | ||
282 | pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); | 261 | pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); |
262 | |||
263 | affs_free_prealloc(inode); | ||
264 | cache_page = (unsigned long)AFFS_I(inode)->i_lc; | ||
283 | if (cache_page) { | 265 | if (cache_page) { |
284 | pr_debug("AFFS: freeing ext cache\n"); | 266 | pr_debug("AFFS: freeing ext cache\n"); |
285 | AFFS_I(inode)->i_lc = NULL; | 267 | AFFS_I(inode)->i_lc = NULL; |
@@ -316,7 +298,7 @@ affs_new_inode(struct inode *dir) | |||
316 | inode->i_ino = block; | 298 | inode->i_ino = block; |
317 | inode->i_nlink = 1; | 299 | inode->i_nlink = 1; |
318 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; | 300 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; |
319 | AFFS_I(inode)->i_opencnt = 0; | 301 | atomic_set(&AFFS_I(inode)->i_opencnt, 0); |
320 | AFFS_I(inode)->i_blkcnt = 0; | 302 | AFFS_I(inode)->i_blkcnt = 0; |
321 | AFFS_I(inode)->i_lc = NULL; | 303 | AFFS_I(inode)->i_lc = NULL; |
322 | AFFS_I(inode)->i_lc_size = 0; | 304 | 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 | switch (type) { | 351 | switch (type) { |
370 | case ST_LINKFILE: | 352 | case ST_LINKFILE: |
371 | case ST_LINKDIR: | 353 | case ST_LINKDIR: |
372 | inode_bh = bh; | ||
373 | retval = -ENOSPC; | 354 | retval = -ENOSPC; |
374 | block = affs_alloc_block(dir, dir->i_ino); | 355 | block = affs_alloc_block(dir, dir->i_ino); |
375 | if (!block) | 356 | if (!block) |
376 | goto err; | 357 | goto err; |
377 | retval = -EIO; | 358 | retval = -EIO; |
359 | inode_bh = bh; | ||
378 | bh = affs_getzeroblk(sb, block); | 360 | bh = affs_getzeroblk(sb, block); |
379 | if (!bh) | 361 | if (!bh) |
380 | goto err; | 362 | goto err; |
diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 2218f1ee71ce..cfcf1b6cf82b 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c | |||
@@ -234,7 +234,8 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
234 | int | 234 | int |
235 | affs_unlink(struct inode *dir, struct dentry *dentry) | 235 | affs_unlink(struct inode *dir, struct dentry *dentry) |
236 | { | 236 | { |
237 | pr_debug("AFFS: unlink(dir=%d, \"%.*s\")\n", (u32)dir->i_ino, | 237 | pr_debug("AFFS: unlink(dir=%d, %lu \"%.*s\")\n", (u32)dir->i_ino, |
238 | dentry->d_inode->i_ino, | ||
238 | (int)dentry->d_name.len, dentry->d_name.name); | 239 | (int)dentry->d_name.len, dentry->d_name.name); |
239 | 240 | ||
240 | return affs_remove_header(dentry); | 241 | return affs_remove_header(dentry); |
@@ -302,7 +303,8 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
302 | int | 303 | int |
303 | affs_rmdir(struct inode *dir, struct dentry *dentry) | 304 | affs_rmdir(struct inode *dir, struct dentry *dentry) |
304 | { | 305 | { |
305 | pr_debug("AFFS: rmdir(dir=%u, \"%.*s\")\n", (u32)dir->i_ino, | 306 | pr_debug("AFFS: rmdir(dir=%u, %lu \"%.*s\")\n", (u32)dir->i_ino, |
307 | dentry->d_inode->i_ino, | ||
306 | (int)dentry->d_name.len, dentry->d_name.name); | 308 | (int)dentry->d_name.len, dentry->d_name.name); |
307 | 309 | ||
308 | return affs_remove_header(dentry); | 310 | return affs_remove_header(dentry); |
diff --git a/fs/affs/super.c b/fs/affs/super.c index 01d25d532541..d214837d5e42 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c | |||
@@ -71,12 +71,18 @@ static struct kmem_cache * affs_inode_cachep; | |||
71 | 71 | ||
72 | static struct inode *affs_alloc_inode(struct super_block *sb) | 72 | static struct inode *affs_alloc_inode(struct super_block *sb) |
73 | { | 73 | { |
74 | struct affs_inode_info *ei; | 74 | struct affs_inode_info *i; |
75 | ei = (struct affs_inode_info *)kmem_cache_alloc(affs_inode_cachep, GFP_KERNEL); | 75 | |
76 | if (!ei) | 76 | i = kmem_cache_alloc(affs_inode_cachep, GFP_KERNEL); |
77 | if (!i) | ||
77 | return NULL; | 78 | return NULL; |
78 | ei->vfs_inode.i_version = 1; | 79 | |
79 | return &ei->vfs_inode; | 80 | i->vfs_inode.i_version = 1; |
81 | i->i_lc = NULL; | ||
82 | i->i_ext_bh = NULL; | ||
83 | i->i_pa_cnt = 0; | ||
84 | |||
85 | return &i->vfs_inode; | ||
80 | } | 86 | } |
81 | 87 | ||
82 | static void affs_destroy_inode(struct inode *inode) | 88 | static void affs_destroy_inode(struct inode *inode) |
@@ -114,8 +120,6 @@ static const struct super_operations affs_sops = { | |||
114 | .alloc_inode = affs_alloc_inode, | 120 | .alloc_inode = affs_alloc_inode, |
115 | .destroy_inode = affs_destroy_inode, | 121 | .destroy_inode = affs_destroy_inode, |
116 | .write_inode = affs_write_inode, | 122 | .write_inode = affs_write_inode, |
117 | .put_inode = affs_put_inode, | ||
118 | .drop_inode = affs_drop_inode, | ||
119 | .delete_inode = affs_delete_inode, | 123 | .delete_inode = affs_delete_inode, |
120 | .clear_inode = affs_clear_inode, | 124 | .clear_inode = affs_clear_inode, |
121 | .put_super = affs_put_super, | 125 | .put_super = affs_put_super, |
diff --git a/fs/inode.c b/fs/inode.c index bf6478130424..18bdce14b70c 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -1153,9 +1153,6 @@ void iput(struct inode *inode) | |||
1153 | 1153 | ||
1154 | BUG_ON(inode->i_state == I_CLEAR); | 1154 | BUG_ON(inode->i_state == I_CLEAR); |
1155 | 1155 | ||
1156 | if (op && op->put_inode) | ||
1157 | op->put_inode(inode); | ||
1158 | |||
1159 | if (atomic_dec_and_lock(&inode->i_count, &inode_lock)) | 1156 | if (atomic_dec_and_lock(&inode->i_count, &inode_lock)) |
1160 | iput_final(inode); | 1157 | iput_final(inode); |
1161 | } | 1158 | } |
diff --git a/fs/locks.c b/fs/locks.c index 663c069b59b3..0ac6b92cb0b6 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -1753,6 +1753,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, | |||
1753 | struct file_lock *file_lock = locks_alloc_lock(); | 1753 | struct file_lock *file_lock = locks_alloc_lock(); |
1754 | struct flock flock; | 1754 | struct flock flock; |
1755 | struct inode *inode; | 1755 | struct inode *inode; |
1756 | struct file *f; | ||
1756 | int error; | 1757 | int error; |
1757 | 1758 | ||
1758 | if (file_lock == NULL) | 1759 | if (file_lock == NULL) |
@@ -1825,7 +1826,15 @@ again: | |||
1825 | * Attempt to detect a close/fcntl race and recover by | 1826 | * Attempt to detect a close/fcntl race and recover by |
1826 | * releasing the lock that was just acquired. | 1827 | * releasing the lock that was just acquired. |
1827 | */ | 1828 | */ |
1828 | if (!error && fcheck(fd) != filp && flock.l_type != F_UNLCK) { | 1829 | /* |
1830 | * we need that spin_lock here - it prevents reordering between | ||
1831 | * update of inode->i_flock and check for it done in close(). | ||
1832 | * rcu_read_lock() wouldn't do. | ||
1833 | */ | ||
1834 | spin_lock(¤t->files->file_lock); | ||
1835 | f = fcheck(fd); | ||
1836 | spin_unlock(¤t->files->file_lock); | ||
1837 | if (!error && f != filp && flock.l_type != F_UNLCK) { | ||
1829 | flock.l_type = F_UNLCK; | 1838 | flock.l_type = F_UNLCK; |
1830 | goto again; | 1839 | goto again; |
1831 | } | 1840 | } |
@@ -1881,6 +1890,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, | |||
1881 | struct file_lock *file_lock = locks_alloc_lock(); | 1890 | struct file_lock *file_lock = locks_alloc_lock(); |
1882 | struct flock64 flock; | 1891 | struct flock64 flock; |
1883 | struct inode *inode; | 1892 | struct inode *inode; |
1893 | struct file *f; | ||
1884 | int error; | 1894 | int error; |
1885 | 1895 | ||
1886 | if (file_lock == NULL) | 1896 | if (file_lock == NULL) |
@@ -1953,7 +1963,10 @@ again: | |||
1953 | * Attempt to detect a close/fcntl race and recover by | 1963 | * Attempt to detect a close/fcntl race and recover by |
1954 | * releasing the lock that was just acquired. | 1964 | * releasing the lock that was just acquired. |
1955 | */ | 1965 | */ |
1956 | if (!error && fcheck(fd) != filp && flock.l_type != F_UNLCK) { | 1966 | spin_lock(¤t->files->file_lock); |
1967 | f = fcheck(fd); | ||
1968 | spin_unlock(¤t->files->file_lock); | ||
1969 | if (!error && f != filp && flock.l_type != F_UNLCK) { | ||
1957 | flock.l_type = F_UNLCK; | 1970 | flock.l_type = F_UNLCK; |
1958 | goto again; | 1971 | goto again; |
1959 | } | 1972 | } |
diff --git a/include/linux/fs.h b/include/linux/fs.h index a1ba005d08e7..7e0fa9e64479 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1289,17 +1289,12 @@ extern ssize_t vfs_readv(struct file *, const struct iovec __user *, | |||
1289 | extern ssize_t vfs_writev(struct file *, const struct iovec __user *, | 1289 | extern ssize_t vfs_writev(struct file *, const struct iovec __user *, |
1290 | unsigned long, loff_t *); | 1290 | unsigned long, loff_t *); |
1291 | 1291 | ||
1292 | /* | ||
1293 | * NOTE: write_inode, delete_inode, clear_inode, put_inode can be called | ||
1294 | * without the big kernel lock held in all filesystems. | ||
1295 | */ | ||
1296 | struct super_operations { | 1292 | struct super_operations { |
1297 | struct inode *(*alloc_inode)(struct super_block *sb); | 1293 | struct inode *(*alloc_inode)(struct super_block *sb); |
1298 | void (*destroy_inode)(struct inode *); | 1294 | void (*destroy_inode)(struct inode *); |
1299 | 1295 | ||
1300 | void (*dirty_inode) (struct inode *); | 1296 | void (*dirty_inode) (struct inode *); |
1301 | int (*write_inode) (struct inode *, int); | 1297 | int (*write_inode) (struct inode *, int); |
1302 | void (*put_inode) (struct inode *); | ||
1303 | void (*drop_inode) (struct inode *); | 1298 | void (*drop_inode) (struct inode *); |
1304 | void (*delete_inode) (struct inode *); | 1299 | void (*delete_inode) (struct inode *); |
1305 | void (*put_super) (struct super_block *); | 1300 | void (*put_super) (struct super_block *); |