new helper: d_obtain_alias
PATCH 2/4 new helper: d_obtain_alias
The calling conventions of d_alloc_anon are rather unfortunate for all users, and it's name is not very descriptive either.
Add d_obtain_alias as a new exported helper that drops the inode reference in the failure case, too and allows to pass-through NULL pointers and inodes to allow for tail-calls in the export operations.
Incidentally this helper already existed as a private function in libfs.c as exportfs_d_alloc so kill that one and switch the callers to d_obtain_alias.
fs/dcache.c +35 -0
@@ -1174,6 +1174,41 @@ struct dentry * d_alloc_anon(struct inodreturn res; } +/** +* d_obtain_alias - find or allocate a dentry for a given inode +* @inode: inode to allocate the dentry for +* +* Obtain a dentry for an inode resulting from NFS filehandle conversion or +* similar open by handle operations. The returned dentry may be anonymous, +* or may have a full name (if the inode was already in the cache). +* +* 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 been released. To make it easier +* to use in export operations a NULL or IS_ERR inode may be passed in +* and will be casted to the corresponding NULL or IS_ERR dentry. +*/ +struct dentry *d_obtain_alias (struct inode *inode) +{ +struct dentry *dentry; + +if (!inode) +return NULL ; +if (IS_ERR (inode)) +return ERR_CAST (inode); + + dentry =d_alloc_anon (inode); +if (!dentry) { +iput (inode); + dentry =ERR_PTR (-ENOMEM ); + } +return dentry; +} +EXPORT_SYMBOL_GPL (d_obtain_alias);/** * d_splice_alias - splice a disconnected dentry into the tree if one exists
fs/libfs.c +2 -24
@@ -732,28 +732,6 @@ out:return ret; } -/* -* This is what d_alloc_anon should have been. Once the exportfs -* argument transition has been finished I will update d_alloc_anon -* to this prototype and this wrapper will go away. --hch -*/ -static struct dentry *exportfs_d_alloc (struct inode *inode) -{ -struct dentry *dentry; - -if (!inode) -return NULL ; -if (IS_ERR (inode)) -return ERR_PTR (PTR_ERR (inode)); - - dentry =d_alloc_anon (inode); -if (!dentry) { -iput (inode); - dentry =ERR_PTR (-ENOMEM ); - } -return dentry; -} -static int fileid_length (int fileid_type) {switch (fileid_type) {
@@ -812,7 +790,7 @@ struct dentry *generic_fh_to_dentry(strubreak ; } -return exportfs_d_alloc (inode); +return d_obtain_alias (inode); }EXPORT_SYMBOL_GPL (generic_fh_to_dentry);
@@ -845,7 +823,7 @@ struct dentry *generic_fh_to_parent(strubreak ; } -return exportfs_d_alloc (inode); +return d_obtain_alias (inode); }EXPORT_SYMBOL_GPL (generic_fh_to_parent);
include/linux/dcache.h +1 -0
@@ -231,6 +231,7 @@ extern struct dentry * d_alloc(struct deextern struct dentry *d_alloc_anon (struct inode *);extern struct dentry *d_splice_alias (struct inode *,struct dentry *);extern struct dentry *d_add_ci (struct dentry *,struct inode *,struct qstr *); +extern struct dentry *d_obtain_alias (struct inode *);extern void shrink_dcache_sb (struct super_block *);extern void shrink_dcache_parent (struct dentry *);extern void shrink_dcache_for_umount (struct super_block *);
Quoted 6 lines · Christoph Hellwig
+/**
+ *d_obtain_alias- find or allocate a dentry for a given inode
+ * @inode: inode to allocate the dentry for
+ *
+ * Obtain a dentry for an inode resulting from NFS filehandle conversion or
+ * similar open by handle operations. The returned dentry may be anonymous,
Quoted 8 lines
+ * or may have a full name (if the inode was already in the cache).
+ *
+ * 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),
^^^^^
ERR_PTR(-ENOMEM)Quoted 1 line
+ * the reference on the inode has been released.
That's useful.
Quoted 4 lines
To make it easier
+ * to use in export operations a NULL orIS_ERRinode may be passed in
+ * and will be casted to the corresponding NULL orIS_ERRdentry.
+ */
Mixing NULL with ERR_PTR() seems like a bad idea. It should be either one or the other but not both.
Miklos
Quoted 5 lines · Miklos Szeredi
Quoted 2 lines
+ * and will be casted to the corresponding NULL or
IS_ERRdentry.
+ */Mixing NULL with
ERR_PTR()seems like a bad idea. It should be either one or the other but not both.
It's how the existing interface works. I think we should move to only ERR_PTR returns, but it's not very high on my todo list.
Quoted 8 lines · Christoph Hellwig
Quoted 5 lines · Miklos Szeredi
Quoted 2 lines
+ * and will be casted to the corresponding NULL or
IS_ERRdentry.
+ */Mixing NULL with
ERR_PTR()seems like a bad idea. It should be either one or the other but not both.It's how the existing interface works.
If you mean ->fh_to_dentry() and ->fh_to_parent(), yes they do work this way. But a NULL return is simply equivalent to a -ESTALE return, so why not turn !inode inot an -ESTALE in d_obtain_alias()? That would fix the interface and the bug in fuse.
Miklos