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