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