3682bdc2955d83437b729dab39ed0d93e459eef0
[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 void
19 osi_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         osi_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     avc->uncred = 0;
150     memset(&(avc->f), 0, sizeof(struct fvcache));
151     avc->cred = NULL;
152 }
153
154 void
155 osi_AttachVnode(struct vcache *avc, int seq) { /* Nada */ }
156
157 void
158 osi_PostPopulateVCache(struct vcache *avc) {
159     vSetType(avc, VREG);
160 }
161
162 /**
163  * osi_ResetRootVCache - Reset the root vcache
164  * Reset the dentry associated with the afs root.
165  * Called from afs_CheckRootVolume when we notice that
166  * the root volume ID has changed.
167  *
168  * @volid: volume ID for the afs root
169  */
170 void
171 osi_ResetRootVCache(afs_uint32 volid)
172 {
173     struct vrequest *treq = NULL;
174     struct vattr vattr;
175     cred_t *credp;
176     struct dentry *dp;
177     struct vcache *vcp;
178     struct inode *root = AFSTOV(afs_globalVp);
179
180     afs_rootFid.Fid.Volume = volid;
181     afs_rootFid.Fid.Vnode = 1;
182     afs_rootFid.Fid.Unique = 1;
183
184     credp = crref();
185     if (afs_CreateReq(&treq, credp))
186         goto out;
187     vcp = afs_GetVCache(&afs_rootFid, treq, NULL, NULL);
188     if (!vcp)
189         goto out;
190     afs_getattr(vcp, &vattr, credp);
191     afs_fill_inode(AFSTOV(vcp), &vattr);
192
193     dp = d_find_alias(root);
194
195 #if defined(HAVE_DCACHE_LOCK)
196     spin_lock(&dcache_lock);
197 #else
198     spin_lock(&AFSTOV(vcp)->i_lock);
199 #endif
200     spin_lock(&dp->d_lock);
201 #if defined(D_ALIAS_IS_HLIST)
202     hlist_del_init(&dp->d_alias);
203     hlist_add_head(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
204 #else
205     list_del_init(&dp->d_alias);
206     list_add(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
207 #endif
208     dp->d_inode = AFSTOV(vcp);
209     spin_unlock(&dp->d_lock);
210 #if defined(HAVE_DCACHE_LOCK)
211     spin_unlock(&dcache_lock);
212 #else
213     spin_unlock(&AFSTOV(vcp)->i_lock);
214 #endif
215     dput(dp);
216
217     AFS_RELE(root);
218     afs_globalVp = vcp;
219 out:
220     crfree(credp);
221     afs_DestroyReq(treq);
222 }