Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] fix reservation discarding in affs

- remove affs_put_inode, so preallocations aren't discared unnecessarily
often.
- remove affs_drop_inode, it's called with a spinlock held, so it can't
use a mutex.
- make i_opencnt atomic
- avoid direct b_count manipulations
- a few allocation failure fixes, so that these are more gracefully
handled now.
Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

authored by

Roman Zippel and committed by
Al Viro
dca3c336 a1530636

+41 -46
+1 -3
fs/affs/affs.h
··· 48 48 * affs fs inode data in memory 49 49 */ 50 50 struct affs_inode_info { 51 - u32 i_opencnt; 51 + atomic_t i_opencnt; 52 52 struct semaphore i_link_lock; /* Protects internal inode access. */ 53 53 struct semaphore i_ext_lock; /* Protects internal inode access. */ 54 54 #define i_hash_lock i_ext_lock ··· 170 170 extern unsigned long affs_parent_ino(struct inode *dir); 171 171 extern struct inode *affs_new_inode(struct inode *dir); 172 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 173 extern void affs_delete_inode(struct inode *inode); 176 174 extern void affs_clear_inode(struct inode *inode); 177 175 extern struct inode *affs_iget(struct super_block *sb,
+17 -8
fs/affs/file.c
··· 48 48 { 49 49 if (atomic_read(&filp->f_count) != 1) 50 50 return 0; 51 - pr_debug("AFFS: open(%d)\n", AFFS_I(inode)->i_opencnt); 52 - AFFS_I(inode)->i_opencnt++; 51 + pr_debug("AFFS: open(%lu,%d)\n", 52 + inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt)); 53 + atomic_inc(&AFFS_I(inode)->i_opencnt); 53 54 return 0; 54 55 } 55 56 ··· 59 58 { 60 59 if (atomic_read(&filp->f_count) != 0) 61 60 return 0; 62 - pr_debug("AFFS: release(%d)\n", AFFS_I(inode)->i_opencnt); 63 - AFFS_I(inode)->i_opencnt--; 64 - if (!AFFS_I(inode)->i_opencnt) 61 + pr_debug("AFFS: release(%lu, %d)\n", 62 + inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt)); 63 + 64 + if (atomic_dec_and_test(&AFFS_I(inode)->i_opencnt)) { 65 + mutex_lock(&inode->i_mutex); 66 + if (inode->i_size != AFFS_I(inode)->mmu_private) 67 + affs_truncate(inode); 65 68 affs_free_prealloc(inode); 69 + mutex_unlock(&inode->i_mutex); 70 + } 66 71 67 72 return 0; 68 73 } ··· 187 180 /* inline the simplest case: same extended block as last time */ 188 181 struct buffer_head *bh = AFFS_I(inode)->i_ext_bh; 189 182 if (ext == AFFS_I(inode)->i_ext_last) 190 - atomic_inc(&bh->b_count); 183 + get_bh(bh); 191 184 else 192 185 /* we have to do more (not inlined) */ 193 186 bh = affs_get_extblock_slow(inode, ext); ··· 313 306 affs_brelse(AFFS_I(inode)->i_ext_bh); 314 307 AFFS_I(inode)->i_ext_last = ext; 315 308 AFFS_I(inode)->i_ext_bh = bh; 316 - atomic_inc(&bh->b_count); 309 + get_bh(bh); 317 310 318 311 return bh; 319 312 ··· 330 323 u32 ext; 331 324 332 325 pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block); 333 - 334 326 335 327 BUG_ON(block > (sector_t)0x7fffffffUL); 336 328 ··· 833 827 res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata); 834 828 if (!res) 835 829 res = mapping->a_ops->write_end(NULL, mapping, size, 0, 0, page, fsdata); 830 + else 831 + inode->i_size = AFFS_I(inode)->mmu_private; 836 832 mark_inode_dirty(inode); 837 833 return; 838 834 } else if (inode->i_size == AFFS_I(inode)->mmu_private) ··· 870 862 blk++; 871 863 } else 872 864 AFFS_HEAD(ext_bh)->first_data = 0; 865 + AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(i); 873 866 size = AFFS_SB(sb)->s_hashsize; 874 867 if (size > blkcnt - blk + i) 875 868 size = blkcnt - blk + i;
+8 -26
fs/affs/inode.c
··· 58 58 AFFS_I(inode)->i_extcnt = 1; 59 59 AFFS_I(inode)->i_ext_last = ~1; 60 60 AFFS_I(inode)->i_protect = prot; 61 - AFFS_I(inode)->i_opencnt = 0; 61 + atomic_set(&AFFS_I(inode)->i_opencnt, 0); 62 62 AFFS_I(inode)->i_blkcnt = 0; 63 63 AFFS_I(inode)->i_lc = NULL; 64 64 AFFS_I(inode)->i_lc_size = 0; ··· 108 108 inode->i_mode |= S_IFDIR; 109 109 } else 110 110 inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR; 111 - if (tail->link_chain) 112 - inode->i_nlink = 2; 113 111 /* Maybe it should be controlled by mount parameter? */ 114 112 //inode->i_mode |= S_ISVTX; 115 113 inode->i_op = &affs_dir_inode_operations; ··· 243 245 } 244 246 245 247 void 246 - affs_put_inode(struct inode *inode) 247 - { 248 - pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); 249 - affs_free_prealloc(inode); 250 - } 251 - 252 - void 253 - affs_drop_inode(struct inode *inode) 254 - { 255 - mutex_lock(&inode->i_mutex); 256 - if (inode->i_size != AFFS_I(inode)->mmu_private) 257 - affs_truncate(inode); 258 - mutex_unlock(&inode->i_mutex); 259 - 260 - generic_drop_inode(inode); 261 - } 262 - 263 - void 264 248 affs_delete_inode(struct inode *inode) 265 249 { 266 250 pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); 267 251 truncate_inode_pages(&inode->i_data, 0); 268 252 inode->i_size = 0; 269 - if (S_ISREG(inode->i_mode)) 270 - affs_truncate(inode); 253 + affs_truncate(inode); 271 254 clear_inode(inode); 272 255 affs_free_block(inode->i_sb, inode->i_ino); 273 256 } ··· 256 277 void 257 278 affs_clear_inode(struct inode *inode) 258 279 { 259 - unsigned long cache_page = (unsigned long) AFFS_I(inode)->i_lc; 280 + unsigned long cache_page; 260 281 261 282 pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); 283 + 284 + affs_free_prealloc(inode); 285 + cache_page = (unsigned long)AFFS_I(inode)->i_lc; 262 286 if (cache_page) { 263 287 pr_debug("AFFS: freeing ext cache\n"); 264 288 AFFS_I(inode)->i_lc = NULL; ··· 298 316 inode->i_ino = block; 299 317 inode->i_nlink = 1; 300 318 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; 301 - AFFS_I(inode)->i_opencnt = 0; 319 + atomic_set(&AFFS_I(inode)->i_opencnt, 0); 302 320 AFFS_I(inode)->i_blkcnt = 0; 303 321 AFFS_I(inode)->i_lc = NULL; 304 322 AFFS_I(inode)->i_lc_size = 0; ··· 351 369 switch (type) { 352 370 case ST_LINKFILE: 353 371 case ST_LINKDIR: 354 - inode_bh = bh; 355 372 retval = -ENOSPC; 356 373 block = affs_alloc_block(dir, dir->i_ino); 357 374 if (!block) 358 375 goto err; 359 376 retval = -EIO; 377 + inode_bh = bh; 360 378 bh = affs_getzeroblk(sb, block); 361 379 if (!bh) 362 380 goto err;
+4 -2
fs/affs/namei.c
··· 234 234 int 235 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 239 (int)dentry->d_name.len, dentry->d_name.name); 239 240 240 241 return affs_remove_header(dentry); ··· 303 302 int 304 303 affs_rmdir(struct inode *dir, struct dentry *dentry) 305 304 { 306 - pr_debug("AFFS: rmdir(dir=%u, \"%.*s\")\n", (u32)dir->i_ino, 305 + pr_debug("AFFS: rmdir(dir=%u, %lu \"%.*s\")\n", (u32)dir->i_ino, 306 + dentry->d_inode->i_ino, 307 307 (int)dentry->d_name.len, dentry->d_name.name); 308 308 309 309 return affs_remove_header(dentry);
+11 -7
fs/affs/super.c
··· 71 71 72 72 static struct inode *affs_alloc_inode(struct super_block *sb) 73 73 { 74 - struct affs_inode_info *ei; 75 - ei = (struct affs_inode_info *)kmem_cache_alloc(affs_inode_cachep, GFP_KERNEL); 76 - if (!ei) 74 + struct affs_inode_info *i; 75 + 76 + i = kmem_cache_alloc(affs_inode_cachep, GFP_KERNEL); 77 + if (!i) 77 78 return NULL; 78 - ei->vfs_inode.i_version = 1; 79 - return &ei->vfs_inode; 79 + 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 88 static void affs_destroy_inode(struct inode *inode) ··· 120 114 .alloc_inode = affs_alloc_inode, 121 115 .destroy_inode = affs_destroy_inode, 122 116 .write_inode = affs_write_inode, 123 - .put_inode = affs_put_inode, 124 - .drop_inode = affs_drop_inode, 125 117 .delete_inode = affs_delete_inode, 126 118 .clear_inode = affs_clear_inode, 127 119 .put_super = affs_put_super,