aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoman Zippel <zippel@linux-m68k.org>2008-04-29 11:02:20 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2008-05-06 13:45:33 -0400
commitdca3c33652e437ed02c30ed3eca3cecd0cc00838 (patch)
tree590db1cd28a19c85532ba8ec8abf5eeb70f993ea
parenta15306365a16380f3bafee9e181ba01231d4acd7 (diff)
[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>
-rw-r--r--fs/affs/affs.h4
-rw-r--r--fs/affs/file.c25
-rw-r--r--fs/affs/inode.c34
-rw-r--r--fs/affs/namei.c6
-rw-r--r--fs/affs/super.c18
5 files changed, 41 insertions, 46 deletions
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 */
50struct affs_inode_info { 50struct 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,
170extern unsigned long affs_parent_ino(struct inode *dir); 170extern unsigned long affs_parent_ino(struct inode *dir);
171extern struct inode *affs_new_inode(struct inode *dir); 171extern struct inode *affs_new_inode(struct inode *dir);
172extern int affs_notify_change(struct dentry *dentry, struct iattr *attr); 172extern int affs_notify_change(struct dentry *dentry, struct iattr *attr);
173extern void affs_put_inode(struct inode *inode);
174extern void affs_drop_inode(struct inode *inode);
175extern void affs_delete_inode(struct inode *inode); 173extern void affs_delete_inode(struct inode *inode);
176extern void affs_clear_inode(struct inode *inode); 174extern void affs_clear_inode(struct inode *inode);
177extern struct inode *affs_iget(struct super_block *sb, 175extern 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
247void 245void
248affs_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
254void
255affs_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
265void
266affs_delete_inode(struct inode *inode) 246affs_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)
277void 256void
278affs_clear_inode(struct inode *inode) 257affs_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)
234int 234int
235affs_unlink(struct inode *dir, struct dentry *dentry) 235affs_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)
302int 303int
303affs_rmdir(struct inode *dir, struct dentry *dentry) 304affs_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
72static struct inode *affs_alloc_inode(struct super_block *sb) 72static 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
82static void affs_destroy_inode(struct inode *inode) 88static 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,