Linux: osi_TryEvictVCache: Don’t skip the first dentry if D_ALIAS_IS_HLIST
[openafs.git] / src / afs / LINUX / osi_vcache.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include "afs/param.h"
12
13 #include "afs/sysincludes.h"    /*Standard vendor system headers */
14 #include "afsincludes.h"        /*AFS-based standard headers */
15
16 int
17 osi_TryEvictVCache(struct vcache *avc, int *slept, int defersleep) {
18     int code;
19
20     struct dentry *dentry;
21     struct inode *inode = AFSTOV(avc);
22 #if defined(D_ALIAS_IS_HLIST) && !defined(HLIST_ITERATOR_NO_NODE)
23     struct hlist_node *p;
24 #endif
25
26     /* First, see if we can evict the inode from the dcache */
27     if (defersleep && avc != afs_globalVp && VREFCOUNT(avc) > 1 && avc->opens == 0) {
28         *slept = 1;
29         ReleaseWriteLock(&afs_xvcache);
30         AFS_GUNLOCK();
31
32 #if defined(HAVE_DCACHE_LOCK)
33         spin_lock(&dcache_lock);
34
35 restart:
36         list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
37             if (d_unhashed(dentry))
38                 continue;
39             dget_locked(dentry);
40
41             spin_unlock(&dcache_lock);
42             if (d_invalidate(dentry) == -EBUSY) {
43                 dput(dentry);
44                 /* perhaps lock and try to continue? (use cur as head?) */
45                 goto inuse;
46             }
47             dput(dentry);
48             spin_lock(&dcache_lock);
49             goto restart;
50         }
51         spin_unlock(&dcache_lock);
52 #else /* HAVE_DCACHE_LOCK */
53         spin_lock(&inode->i_lock);
54
55 restart:
56 #if defined(D_ALIAS_IS_HLIST)
57 # if defined(HLIST_ITERATOR_NO_NODE)
58         hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
59 # else
60         hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
61 # endif
62 #else
63         list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
64 #endif
65             spin_lock(&dentry->d_lock);
66             if (d_unhashed(dentry)) {
67                 spin_unlock(&dentry->d_lock);
68                 continue;
69             }
70             spin_unlock(&dentry->d_lock);
71             dget(dentry);
72
73             spin_unlock(&inode->i_lock);
74             if (d_invalidate(dentry) == -EBUSY) {
75                 dput(dentry);
76                 /* perhaps lock and try to continue? (use cur as head?) */
77                 goto inuse;
78             }
79             dput(dentry);
80             spin_lock(&inode->i_lock);
81             goto restart;
82         }
83         spin_unlock(&inode->i_lock);
84 #endif /* HAVE_DCACHE_LOCK */
85 inuse:
86         AFS_GLOCK();
87         ObtainWriteLock(&afs_xvcache, 733);
88     }
89
90     /* See if we can evict it from the VLRUQ */
91     if (VREFCOUNT_GT(avc,0) && !VREFCOUNT_GT(avc,1) && avc->opens == 0
92         && (avc->f.states & CUnlinkedDel) == 0) {
93         int didsleep = *slept;
94
95         code = afs_FlushVCache(avc, slept);
96         /* flushvcache wipes slept; restore slept if we did before */
97         if (didsleep)
98             *slept = didsleep;
99
100         if (code == 0)
101             return 1;
102     }
103
104     return 0;
105 }
106
107 struct vcache *
108 osi_NewVnode(void)
109 {
110     struct inode *ip;
111     struct vcache *tvc;
112
113     AFS_GUNLOCK();
114     ip = new_inode(afs_globalVFS);
115     if (!ip)
116         osi_Panic("afs_NewVCache: no more inodes");
117     AFS_GLOCK();
118 #if defined(STRUCT_SUPER_OPERATIONS_HAS_ALLOC_INODE)
119     tvc = VTOAFS(ip);
120 #else
121     tvc = afs_osi_Alloc(sizeof(struct vcache));
122     ip->u.generic_ip = tvc;
123     tvc->v = ip;
124 #endif
125
126     return tvc;
127 }
128
129 void
130 osi_PrePopulateVCache(struct vcache *avc) {
131     avc->uncred = 0;
132     memset(&(avc->f), 0, sizeof(struct fvcache));
133     avc->cred = NULL;
134 }
135
136 void
137 osi_AttachVnode(struct vcache *avc, int seq) { /* Nada */ }
138
139 void
140 osi_PostPopulateVCache(struct vcache *avc) {
141     vSetType(avc, VREG);
142 }
143