52830c555b312f1a0e567d1ac581debfc9d78007
[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 #include "osi_compat.h"
17
18 static void
19 TryEvictDentries(struct vcache *avc)
20 {
21 #ifndef D_INVALIDATE_IS_VOID
22     struct dentry *dentry;
23 #endif
24     struct inode *inode = AFSTOV(avc);
25 #if defined(D_ALIAS_IS_HLIST) && !defined(HLIST_ITERATOR_NO_NODE)
26     struct hlist_node *p;
27 #endif
28
29 #if defined(D_INVALIDATE_IS_VOID)
30     /* At this kernel level, d_invalidate always succeeds;
31      * that is, it will now invalidate even an active directory,
32      * Therefore we must use a different method to evict dentries.
33      */
34     d_prune_aliases(inode);
35 #else
36 #if defined(HAVE_DCACHE_LOCK)
37     spin_lock(&dcache_lock);
38
39 restart:
40     list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
41         if (d_unhashed(dentry))
42             continue;
43         dget_locked(dentry);
44
45         spin_unlock(&dcache_lock);
46         if (d_invalidate(dentry) == -EBUSY) {
47             dput(dentry);
48             /* perhaps lock and try to continue? (use cur as head?) */
49             goto inuse;
50         }
51         dput(dentry);
52         spin_lock(&dcache_lock);
53         goto restart;
54     }
55     spin_unlock(&dcache_lock);
56 #else /* HAVE_DCACHE_LOCK */
57     spin_lock(&inode->i_lock);
58
59 restart:
60 #if defined(D_ALIAS_IS_HLIST)
61 # if defined(HLIST_ITERATOR_NO_NODE)
62     hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
63 # else
64     hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
65 # endif
66 #else
67     list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
68 #endif
69         spin_lock(&dentry->d_lock);
70         if (d_unhashed(dentry)) {
71             spin_unlock(&dentry->d_lock);
72             continue;
73         }
74         spin_unlock(&dentry->d_lock);
75         dget(dentry);
76
77         spin_unlock(&inode->i_lock);
78         if (afs_d_invalidate(dentry) == -EBUSY) {
79             dput(dentry);
80             /* perhaps lock and try to continue? (use cur as head?) */
81             goto inuse;
82         }
83         dput(dentry);
84         spin_lock(&inode->i_lock);
85         goto restart;
86     }
87     spin_unlock(&inode->i_lock);
88 #endif /* HAVE_DCACHE_LOCK */
89 inuse:
90 #endif /* D_INVALIDATE_IS_VOID */
91     return;
92 }
93
94
95 int
96 osi_TryEvictVCache(struct vcache *avc, int *slept, int defersleep)
97 {
98     int code;
99
100     /* First, see if we can evict the inode from the dcache */
101     if (defersleep && avc != afs_globalVp && VREFCOUNT(avc) > 1
102         && avc->opens == 0) {
103         *slept = 1;
104         AFS_FAST_HOLD(avc);
105         ReleaseWriteLock(&afs_xvcache);
106         AFS_GUNLOCK();
107
108         TryEvictDentries(avc);
109
110         AFS_GLOCK();
111         ObtainWriteLock(&afs_xvcache, 733);
112         AFS_FAST_RELE(avc);
113     }
114
115     /* See if we can evict it from the VLRUQ */
116     if (VREFCOUNT_GT(avc, 0) && !VREFCOUNT_GT(avc, 1) && avc->opens == 0
117         && (avc->f.states & CUnlinkedDel) == 0) {
118         int didsleep = *slept;
119
120         code = afs_FlushVCache(avc, slept);
121         /* flushvcache wipes slept; restore slept if we did before */
122         if (didsleep)
123             *slept = didsleep;
124
125         if (code == 0)
126             return 1;
127     }
128
129     return 0;
130 }
131
132 struct vcache *
133 osi_NewVnode(void)
134 {
135     struct inode *ip;
136     struct vcache *tvc;
137
138     AFS_GUNLOCK();
139     ip = new_inode(afs_globalVFS);
140     if (!ip)
141         osi_Panic("afs_NewVCache: no more inodes");
142     AFS_GLOCK();
143 #if defined(STRUCT_SUPER_OPERATIONS_HAS_ALLOC_INODE)
144     tvc = VTOAFS(ip);
145 #else
146     tvc = afs_osi_Alloc(sizeof(struct vcache));
147     ip->u.generic_ip = tvc;
148     tvc->v = ip;
149 #endif
150
151     INIT_LIST_HEAD(&tvc->pagewriters);
152     spin_lock_init(&tvc->pagewriter_lock);
153
154     return tvc;
155 }
156
157 void
158 osi_PrePopulateVCache(struct vcache *avc)
159 {
160     avc->uncred = 0;
161     memset(&(avc->f), 0, sizeof(struct fvcache));
162     avc->cred = NULL;
163 }
164
165 void
166 osi_AttachVnode(struct vcache *avc, int seq)
167 {
168     /* Nada */
169 }
170
171 void
172 osi_PostPopulateVCache(struct vcache *avc)
173 {
174     vSetType(avc, VREG);
175 }
176
177 /**
178  * osi_ResetRootVCache - Reset the root vcache
179  * Reset the dentry associated with the afs root.
180  * Called from afs_CheckRootVolume when we notice that
181  * the root volume ID has changed.
182  *
183  * @volid: volume ID for the afs root
184  */
185 void
186 osi_ResetRootVCache(afs_uint32 volid)
187 {
188     struct vrequest *treq = NULL;
189     struct vattr vattr;
190     cred_t *credp;
191     struct dentry *dp;
192     struct vcache *vcp;
193     struct inode *root = AFSTOV(afs_globalVp);
194
195     afs_rootFid.Fid.Volume = volid;
196     afs_rootFid.Fid.Vnode = 1;
197     afs_rootFid.Fid.Unique = 1;
198
199     credp = crref();
200     if (afs_CreateReq(&treq, credp))
201         goto out;
202     vcp = afs_GetVCache(&afs_rootFid, treq, NULL, NULL);
203     if (!vcp)
204         goto out;
205     afs_getattr(vcp, &vattr, credp);
206     afs_fill_inode(AFSTOV(vcp), &vattr);
207
208     dp = d_find_alias(root);
209
210 #if defined(HAVE_DCACHE_LOCK)
211     spin_lock(&dcache_lock);
212 #else
213     spin_lock(&AFSTOV(vcp)->i_lock);
214 #endif
215     spin_lock(&dp->d_lock);
216 #if defined(D_ALIAS_IS_HLIST)
217     hlist_del_init(&dp->d_alias);
218     hlist_add_head(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
219 #else
220     list_del_init(&dp->d_alias);
221     list_add(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
222 #endif
223     dp->d_inode = AFSTOV(vcp);
224     spin_unlock(&dp->d_lock);
225 #if defined(HAVE_DCACHE_LOCK)
226     spin_unlock(&dcache_lock);
227 #else
228     spin_unlock(&AFSTOV(vcp)->i_lock);
229 #endif
230     dput(dp);
231
232     AFS_RELE(root);
233     afs_globalVp = vcp;
234 out:
235     crfree(credp);
236     afs_DestroyReq(treq);
237 }