factor out duplicated code for handle2dentry conversation
Subsystems (3)
PATCH 1/1 factor out duplicated code for handle2dentry conversation
Every filesystem that implements methods to convert from a NFS filehandle to a dentry duplicates this code (there are even more out of tree). Factor it out in common code. The function d_alloc_anon() is already present in 2.5 with the same interface but a slightly different implementation.
Also cleanup d_find_alias (that has a very similar to d_alloc_anon and yet not mergeable function body) to use proper list handling functions.
fs/dcache.c +58 -13
@@ -242,24 +242,22 @@ struct dentry * dget_locked(struct dentrstruct dentry *d_find_alias (struct inode *inode) { -struct list_head *head, *next, *tmp; -struct dentry *alias; +struct dentry *dentry; +struct list_head *p;spin_lock (&dcache_lock); - head = &inode->i_dentry; - next = inode->i_dentry.next; -while (next != head) { - tmp = next; - next = tmp->next; - alias = list_entry(tmp, struct dentry, d_alias); -if (!list_empty (&alias->d_hash)) { -__dget_locked (alias); -spin_unlock (&dcache_lock); -return alias; - } +list_for_each (p, &inode->i_dentry) { + dentry = list_entry(p, struct dentry, d_alias); +if (!list_empty (&dentry->d_hash)) + goto found; }spin_unlock (&dcache_lock);return NULL ; + +found: +__dget_locked (dentry); +spin_unlock (&dcache_lock); +return dentry; }/*
@@ -659,6 +657,53 @@ void d_instantiate(struct dentry *entry, }/** +* d_alloc_anon - allocate an anonymous dentry +* @inode: inode to allocate the dentry for +* +* This is similar to d_alloc_root. It is used by filesystems when +* creating a dentry for a given inode, often in the process of +* mapping a filehandle to a dentry. The returned dentry may be +* anonymous, or may have a full name (if the inode was already +* in the cache). The file system may need to make further +* efforts to connect this dentry into the dcache properly. +* +* When called on a directory inode, we must ensure that +* the inode only ever has one dentry. If a dentry is +* found, that is returned instead of allocating a new one. +* +* On successful return, the reference to the inode has been transferred +* to the dentry. If %NULL is returned (indicating kmalloc failure), +* the reference on the inode has not been released. +*/ + +struct dentry *d_alloc_anon (struct inode *inode) +{ +struct dentry *dentry; +struct list_head *p; + +/* Try to find a dentry. If possible, get a well-connected one. */ +spin_lock (&dcache_lock); +list_for_each (p, &inode->i_dentry) { + dentry = list_entry(p, struct dentry, d_alias); +if (!(dentry->d_flags &DCACHE_NFSD_DISCONNECTED )) + goto found; + } +spin_unlock (&dcache_lock); + +/* Didn't find dentry. Create anonymous dcache entry. */ + dentry =d_alloc_root (inode); +if (dentry) + dentry->d_flags |=DCACHE_NFSD_DISCONNECTED ; +return dentry; + +found: +dget_locked (dentry); +spin_unlock (&dcache_lock); +iput (inode); +return dentry; +} + +/** * d_alloc_root - allocate root dentry * @root_inode: inode to allocate the root for *
fs/fat/inode.c +3 -23
@@ -430,7 +430,6 @@ struct dentry *fat_fh_to_dentry(struct s int len, int fhtype, int parent) { struct inode *inode = NULL; -struct list_head *lp;struct dentry *result;if (fhtype !=3 )
@@ -477,33 +476,14 @@ struct dentry *fat_fh_to_dentry(struct sif (!inode)return ERR_PTR (-ESTALE ); - -/* now to find a dentry. -* If possible, get a well-connected one -* -* Given the way that we found the inode, it *MUST* be -* well-connected, but it is easiest to just copy the -* code. -*/ -spin_lock (&dcache_lock); -for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) { - result = list_entry(lp,struct dentry, d_alias); -if (! (result->d_flags &DCACHE_NFSD_DISCONNECTED )) { -dget_locked (result); - result->d_vfs_flags |=DCACHE_REFERENCED ; -spin_unlock (&dcache_lock); -iput (inode); -return result; - } - } -spin_unlock (&dcache_lock); - result =d_alloc_root (inode); + + result =d_alloc_anon (inode);if (result ==NULL ) {iput (inode);return ERR_PTR (-ENOMEM ); } result->d_op = sb->s_root->d_op; - result->d_flags |=DCACHE_NFSD_DISCONNECTED ; + result->d_vfs_flags |=DCACHE_REFERENCED ;return result;
fs/nfsd/nfsfh.c +4 -18
@@ -135,7 +135,6 @@ static struct dentry *nfsd_iget(struct s* of 0 means "accept any" */ struct inode *inode; -struct list_head *lp;struct dentry *result;if (ino ==0 )return ERR_PTR (-ESTALE );
@@ -155,27 +154,14 @@ static struct dentry *nfsd_iget(struct siput (inode);return ERR_PTR (-ESTALE ); } -/* now to find a dentry. -* If possible, get a well-connected one -*/ -spin_lock (&dcache_lock); -for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) { - result = list_entry(lp,struct dentry, d_alias); -if (! (result->d_flags &DCACHE_NFSD_DISCONNECTED )) { -dget_locked (result); - result->d_vfs_flags |=DCACHE_REFERENCED ; -spin_unlock (&dcache_lock); -iput (inode); -return result; - } - } -spin_unlock (&dcache_lock); - result =d_alloc_root (inode); + + + result =d_alloc_anon (inode);if (result ==NULL ) {iput (inode);return ERR_PTR (-ENOMEM ); } - result->d_flags |=DCACHE_NFSD_DISCONNECTED ; + result->d_vfs_flags |=DCACHE_REFERENCED ;return result; }
fs/reiserfs/inode.c +2 -18
@@ -1229,7 +1229,6 @@ struct dentry *reiserfs_fh_to_dentry(str int len, int fhtype, int parent) { struct cpu_key key ;struct inode *inode =NULL ; -struct list_head *lp;struct dentry *result;/* fhtype happens to reflect the number of u32s encoded.
@@ -1281,27 +1280,12 @@ out:if (!inode)return ERR_PTR (-ESTALE ) ; -/* now to find a dentry. -* If possible, get a well-connected one -*/ -spin_lock (&dcache_lock); -for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) { - result = list_entry(lp,struct dentry, d_alias); -if (! (result->d_flags &DCACHE_NFSD_DISCONNECTED )) { -dget_locked (result); - result->d_vfs_flags |=DCACHE_REFERENCED ; -spin_unlock (&dcache_lock); -iput (inode); -return result; - } - } -spin_unlock (&dcache_lock); - result =d_alloc_root (inode); + result =d_alloc_anon (inode);if (result ==NULL ) {iput (inode);return ERR_PTR (-ENOMEM ); } - result->d_flags |=DCACHE_NFSD_DISCONNECTED ; + result->d_vfs_flags |=DCACHE_REFERENCED ;return result; }
include/linux/dcache.h +1 -0
@@ -165,6 +165,7 @@ extern void d_delete(struct dentry *);/* allocate/de-allocate */ extern struct dentry *d_alloc (struct dentry *,const struct qstr *); +extern struct dentry *d_alloc_anon (struct inode *);extern void shrink_dcache_sb (struct super_block *);extern void shrink_dcache_parent (struct dentry *);extern int d_invalidate (struct dentry *);
kernel/ksyms.c +1 -0
@@ -162,6 +162,7 @@ EXPORT_SYMBOL(d_invalidate); /* May be iEXPORT_SYMBOL (d_move);EXPORT_SYMBOL (d_instantiate);EXPORT_SYMBOL (d_alloc); +EXPORT_SYMBOL (d_alloc_anon);EXPORT_SYMBOL (d_lookup);EXPORT_SYMBOL (__d_path);EXPORT_SYMBOL (mark_buffer_dirty);