Cleanup usage of LINUX_VERSION_CODE for older kernels
[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 TryEvictDirDentries(struct inode *inode)
20 {
21     struct dentry *dentry;
22 #if defined(D_ALIAS_IS_HLIST) && !defined(HLIST_ITERATOR_NO_NODE)
23     struct hlist_node *p;
24 #endif
25
26     afs_d_alias_lock(inode);
27
28  restart:
29 #if defined(D_ALIAS_IS_HLIST)
30 # if defined(HLIST_ITERATOR_NO_NODE)
31     hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
32 # else
33     hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
34 # endif
35 #else
36     list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
37 #endif
38         spin_lock(&dentry->d_lock);
39         if (d_unhashed(dentry)) {
40             spin_unlock(&dentry->d_lock);
41             continue;
42         }
43         spin_unlock(&dentry->d_lock);
44         afs_linux_dget(dentry);
45
46         afs_d_alias_unlock(inode);
47
48         /*
49          * Once we have dropped the d_alias lock (above), it is no longer safe
50          * to 'continue' our iteration over d_alias because the list may change
51          * out from under us.  Therefore, we must either leave the loop, or
52          * restart from the beginning.  To avoid looping forever, we must only
53          * restart if we know we've d_drop'd an alias.  In all other cases we
54          * must leave the loop.
55          */
56
57         /*
58          * For a long time we used d_invalidate() for this purpose, but
59          * using shrink_dcache_parent() and checking the refcount ourselves is
60          * better, for two reasons: it avoids causing ENOENT issues for the
61          * CWD in linux versions since 3.11, and it avoids dropping Linux
62          * submounts.
63          *
64          * For non-fakestat, AFS mountpoints look like directories and end up here.
65          */
66
67         shrink_dcache_parent(dentry);
68         spin_lock(&dentry->d_lock);
69         if (afs_dentry_count(dentry) > 1)       /* still has references */ {
70             if (dentry->d_inode != NULL) /* is not a negative dentry */ {
71                 spin_unlock(&dentry->d_lock);
72                 dput(dentry);
73                 goto inuse;
74             }
75         }
76         /*
77          * This is either a negative dentry, or a dentry with no references.
78          * Either way, it is okay to unhash it now.
79          * Do so under the d_lock (that is, via __d_drop() instead of d_drop())
80          * to avoid a race with another process picking up a reference.
81          */
82         __d_drop(dentry);
83         spin_unlock(&dentry->d_lock);
84
85         dput(dentry);
86         afs_d_alias_lock(inode);
87         goto restart;
88     }
89     afs_d_alias_unlock(inode);
90
91  inuse:
92     return;
93 }
94
95
96 int
97 osi_TryEvictVCache(struct vcache *avc, int *slept, int defersleep)
98 {
99     int code;
100
101     /* First, see if we can evict the inode from the dcache */
102     if (defersleep && avc != afs_globalVp && VREFCOUNT(avc) > 1
103         && avc->opens == 0) {
104         struct inode *ip = AFSTOV(avc);
105
106         if (osi_vnhold(avc) != 0) {
107             /* Can't grab a ref on avc; bail out. */
108             return 0;
109         }
110         *slept = 1;
111         ReleaseWriteLock(&afs_xvcache);
112         AFS_GUNLOCK();
113
114         if (S_ISDIR(ip->i_mode))
115             TryEvictDirDentries(ip);
116         else
117             d_prune_aliases(ip);
118
119         AFS_GLOCK();
120         ObtainWriteLock(&afs_xvcache, 733);
121         AFS_FAST_RELE(avc);
122     }
123
124     /* See if we can evict it from the VLRUQ */
125     if (VREFCOUNT_GT(avc, 0) && !VREFCOUNT_GT(avc, 1) && avc->opens == 0
126         && (avc->f.states & CUnlinkedDel) == 0) {
127         int didsleep = *slept;
128
129         code = afs_FlushVCache(avc, slept);
130         /* flushvcache wipes slept; restore slept if we did before */
131         if (didsleep)
132             *slept = didsleep;
133
134         if (code == 0)
135             return 1;
136     }
137
138     return 0;
139 }
140
141 struct vcache *
142 osi_NewVnode(void)
143 {
144     struct inode *ip;
145     struct vcache *tvc;
146
147     AFS_GUNLOCK();
148     ip = new_inode(afs_globalVFS);
149     AFS_GLOCK();
150     if (ip == NULL) {
151         return NULL;
152     }
153 #if defined(STRUCT_SUPER_OPERATIONS_HAS_ALLOC_INODE)
154     tvc = VTOAFS(ip);
155 #else
156     tvc = afs_osi_Alloc(sizeof(struct vcache));
157     if (tvc == NULL) {
158         iput(ip);
159         return NULL;
160     }
161     ip->u.generic_ip = tvc;
162     tvc->v = ip;
163 #endif
164
165     INIT_LIST_HEAD(&tvc->pagewriters);
166     spin_lock_init(&tvc->pagewriter_lock);
167
168     return tvc;
169 }
170
171 void
172 osi_PrePopulateVCache(struct vcache *avc)
173 {
174     avc->uncred = 0;
175     memset(&(avc->f), 0, sizeof(struct fvcache));
176     avc->cred = NULL;
177 }
178
179 void
180 osi_AttachVnode(struct vcache *avc, int seq)
181 {
182     /* Nada */
183 }
184
185 void
186 osi_PostPopulateVCache(struct vcache *avc)
187 {
188     vSetType(avc, VREG);
189 }
190
191 /**
192  * osi_ResetRootVCache - Reset the root vcache
193  * Reset the dentry associated with the afs root.
194  * Called from afs_CheckRootVolume when we notice that
195  * the root volume ID has changed.
196  *
197  * @volid: volume ID for the afs root
198  */
199 void
200 osi_ResetRootVCache(afs_uint32 volid)
201 {
202     struct vrequest *treq = NULL;
203     struct vattr vattr;
204     cred_t *credp;
205     struct dentry *dp;
206     struct vcache *vcp;
207     struct inode *root = AFSTOV(afs_globalVp);
208
209     afs_rootFid.Fid.Volume = volid;
210     afs_rootFid.Fid.Vnode = 1;
211     afs_rootFid.Fid.Unique = 1;
212
213     credp = crref();
214     if (afs_CreateReq(&treq, credp))
215         goto out;
216     vcp = afs_GetVCache(&afs_rootFid, treq);
217     if (!vcp)
218         goto out;
219     afs_getattr(vcp, &vattr, credp);
220     afs_fill_inode(AFSTOV(vcp), &vattr);
221
222     dp = d_find_alias(root);
223
224     afs_d_alias_lock(AFSTOV(vcp));
225
226     spin_lock(&dp->d_lock);
227 #if defined(D_ALIAS_IS_HLIST)
228     hlist_del_init(&dp->d_alias);
229     hlist_add_head(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
230 #else
231     list_del_init(&dp->d_alias);
232     list_add(&dp->d_alias, &(AFSTOV(vcp)->i_dentry));
233 #endif
234     dp->d_inode = AFSTOV(vcp);
235     spin_unlock(&dp->d_lock);
236
237     afs_d_alias_unlock(AFSTOV(vcp));
238
239     dput(dp);
240
241     AFS_RELE(root);
242     afs_globalVp = vcp;
243  out:
244     crfree(credp);
245     afs_DestroyReq(treq);
246 }
247
248 int
249 osi_vnhold(struct vcache *avc)
250 {
251     VN_HOLD(AFSTOV(avc));
252     return 0;
253 }