Track negative entries v3

Track negative dentries by recording the generation number of the parent
directory in d_fsdata. The generation number for the parent directory is
recorded in the inode_info, which increments every time the lock on the
directory is dropped.

If the generation number of the parent directory and the negative dentry
matches, there is no need to perform the revalidate, else a revalidate
is forced. This improves performance in situations where nodes look for
the same non-existent file multiple times.

Thanks Mark for explaining the DLM sequence.

Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.de>
Signed-off-by: Joel Becker <joel.becker@oracle.com>

authored by Goldwyn Rodrigues and committed by Joel Becker 5e98d492 b4d693fc

+42 -5
+29 -4
fs/ocfs2/dcache.c
··· 40 #include "inode.h" 41 #include "super.h" 42 43 44 static int ocfs2_dentry_revalidate(struct dentry *dentry, 45 struct nameidata *nd) ··· 59 mlog_entry("(0x%p, '%.*s')\n", dentry, 60 dentry->d_name.len, dentry->d_name.name); 61 62 - /* Never trust a negative dentry - force a new lookup. */ 63 if (inode == NULL) { 64 - mlog(0, "negative dentry: %.*s\n", dentry->d_name.len, 65 - dentry->d_name.name); 66 - goto bail; 67 } 68 69 BUG_ON(!osb); ··· 113 goto bail; 114 } 115 116 ret = 1; 117 118 bail: ··· 244 */ 245 if (!inode) 246 return 0; 247 248 if (dl) { 249 mlog_bug_on_msg(dl->dl_parent_blkno != parent_blkno, ··· 476 477 out: 478 iput(inode); 479 } 480 481 /*
··· 40 #include "inode.h" 41 #include "super.h" 42 43 + void ocfs2_dentry_attach_gen(struct dentry *dentry) 44 + { 45 + unsigned long gen = 46 + OCFS2_I(dentry->d_parent->d_inode)->ip_dir_lock_gen; 47 + BUG_ON(dentry->d_inode); 48 + dentry->d_fsdata = (void *)gen; 49 + } 50 + 51 52 static int ocfs2_dentry_revalidate(struct dentry *dentry, 53 struct nameidata *nd) ··· 51 mlog_entry("(0x%p, '%.*s')\n", dentry, 52 dentry->d_name.len, dentry->d_name.name); 53 54 + /* For a negative dentry - 55 + * check the generation number of the parent and compare with the 56 + * one stored in the inode. 57 + */ 58 if (inode == NULL) { 59 + unsigned long gen = (unsigned long) dentry->d_fsdata; 60 + unsigned long pgen = 61 + OCFS2_I(dentry->d_parent->d_inode)->ip_dir_lock_gen; 62 + mlog(0, "negative dentry: %.*s parent gen: %lu " 63 + "dentry gen: %lu\n", 64 + dentry->d_name.len, dentry->d_name.name, pgen, gen); 65 + if (gen != pgen) 66 + goto bail; 67 + goto valid; 68 } 69 70 BUG_ON(!osb); ··· 96 goto bail; 97 } 98 99 + valid: 100 ret = 1; 101 102 bail: ··· 226 */ 227 if (!inode) 228 return 0; 229 + 230 + if (!dentry->d_inode && dentry->d_fsdata) { 231 + /* Converting a negative dentry to positive 232 + Clear dentry->d_fsdata */ 233 + dentry->d_fsdata = dl = NULL; 234 + } 235 236 if (dl) { 237 mlog_bug_on_msg(dl->dl_parent_blkno != parent_blkno, ··· 452 453 out: 454 iput(inode); 455 + ocfs2_dentry_attach_gen(dentry); 456 } 457 458 /*
+1
fs/ocfs2/dcache.h
··· 64 struct inode *old_dir, struct inode *new_dir); 65 66 extern spinlock_t dentry_attach_lock; 67 68 #endif /* OCFS2_DCACHE_H */
··· 64 struct inode *old_dir, struct inode *new_dir); 65 66 extern spinlock_t dentry_attach_lock; 67 + void ocfs2_dentry_attach_gen(struct dentry *dentry); 68 69 #endif /* OCFS2_DCACHE_H */
+8
fs/ocfs2/dlmglue.c
··· 3635 { 3636 struct inode *inode; 3637 struct address_space *mapping; 3638 3639 inode = ocfs2_lock_res_inode(lockres); 3640 mapping = inode->i_mapping; 3641 3642 if (!S_ISREG(inode->i_mode)) 3643 goto out;
··· 3635 { 3636 struct inode *inode; 3637 struct address_space *mapping; 3638 + struct ocfs2_inode_info *oi; 3639 3640 inode = ocfs2_lock_res_inode(lockres); 3641 mapping = inode->i_mapping; 3642 + 3643 + if (S_ISDIR(inode->i_mode)) { 3644 + oi = OCFS2_I(inode); 3645 + oi->ip_dir_lock_gen++; 3646 + mlog(0, "generation: %u\n", oi->ip_dir_lock_gen); 3647 + goto out; 3648 + } 3649 3650 if (!S_ISREG(inode->i_mode)) 3651 goto out;
+1
fs/ocfs2/inode.c
··· 335 else 336 inode->i_fop = &ocfs2_dops_no_plocks; 337 i_size_write(inode, le64_to_cpu(fe->i_size)); 338 break; 339 case S_IFLNK: 340 if (ocfs2_inode_is_fast_symlink(inode))
··· 335 else 336 inode->i_fop = &ocfs2_dops_no_plocks; 337 i_size_write(inode, le64_to_cpu(fe->i_size)); 338 + OCFS2_I(inode)->ip_dir_lock_gen = 1; 339 break; 340 case S_IFLNK: 341 if (ocfs2_inode_is_fast_symlink(inode))
+1
fs/ocfs2/inode.h
··· 67 /* Only valid if the inode is the dir. */ 68 u32 ip_last_used_slot; 69 u64 ip_last_used_group; 70 71 struct ocfs2_alloc_reservation ip_la_data_resv; 72 };
··· 67 /* Only valid if the inode is the dir. */ 68 u32 ip_last_used_slot; 69 u64 ip_last_used_group; 70 + u32 ip_dir_lock_gen; 71 72 struct ocfs2_alloc_reservation ip_la_data_resv; 73 };
+2 -1
fs/ocfs2/namei.c
··· 171 ret = ERR_PTR(status); 172 goto bail_unlock; 173 } 174 - } 175 176 bail_unlock: 177 /* Don't drop the cluster lock until *after* the d_add --
··· 171 ret = ERR_PTR(status); 172 goto bail_unlock; 173 } 174 + } else 175 + ocfs2_dentry_attach_gen(dentry); 176 177 bail_unlock: 178 /* Don't drop the cluster lock until *after* the d_add --