e7c8620620bbb1342728b9c8a0caf2f4663d3d1b
[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     afs_d_alias_lock(inode);
29
30 restart:
31     list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
32         if (d_unhashed(dentry))
33             continue;
34         afs_linux_dget(dentry);
35
36         afs_d_alias_unlock(inode);
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         afs_d_alias_lock(inode);
44         goto restart;
45     }
46     afs_d_alias_unlock(inode);
47 #else /* HAVE_DCACHE_LOCK */
48     afs_d_alias_lock(inode);
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         afs_linux_dget(dentry);
67
68         afs_d_alias_unlock(inode);
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         afs_d_alias_lock(inode);
76         goto restart;
77     }
78     afs_d_alias_unlock(inode);
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     afs_d_alias_lock(AFSTOV(vcp));
201
202     spin_lock(&dp->d_lock);
203 #if defined(D_ALIAS_IS_HLIST)
204     hlist_del_init(&dp->d_alias);
205     hlist_add_head(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
206 #else
207     list_del_init(&dp->d_alias);
208     list_add(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
209 #endif
210     dp->d_inode = AFSTOV(vcp);
211     spin_unlock(&dp->d_lock);
212
213     afs_d_alias_unlock(AFSTOV(vcp));
214
215     dput(dp);
216
217     AFS_RELE(root);
218     afs_globalVp = vcp;
219 out:
220     crfree(credp);
221     afs_DestroyReq(treq);
222 }