{
struct vcache *vcp = VTOAFS(ip);
struct dentry *first = NULL, *ret = NULL, *cur;
+#if defined(D_ALIAS_IS_HLIST)
+ struct hlist_node *p;
+#endif
/* general strategy:
* if vcp->target_link is set, and can be found in ip->i_dentry, use that.
spin_lock(&ip->i_lock);
# endif
+#if defined(D_ALIAS_IS_HLIST)
+ hlist_for_each_entry(cur, p, &ip->i_dentry, d_alias) {
+#else
list_for_each_entry_reverse(cur, &ip->i_dentry, d_alias) {
+#endif
if (!vcp->target_link || cur == vcp->target_link) {
ret = cur;
* name is in kernel space at this point.
*/
static int
-#if defined(IOP_MKDIR_TAKES_UMODE_T)
+#if defined(IOP_CREATE_TAKES_UMODE_T)
afs_linux_create(struct inode *dip, struct dentry *dp, umode_t mode,
struct nameidata *nd)
#else
if (vcp) {
struct vattr vattr;
+ struct vcache *parent_vc = VTOAFS(dip);
+
+ if (parent_vc == vcp) {
+ /* This is possible if the parent dir is a mountpoint to a volume,
+ * and the dir entry we looked up is a mountpoint to the same
+ * volume. Linux cannot cope with this, so return an error instead
+ * of risking a deadlock or panic. */
+ afs_PutVCache(vcp);
+ code = EDEADLK;
+ AFS_GUNLOCK();
+ goto done;
+ }
ip = AFSTOV(vcp);
afs_getattr(vcp, &vattr, credp);
}
newdp = d_splice_alias(ip, dp);
+ done:
crfree(credp);
/* It's ok for the file to not be found. That's noted by the caller by