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