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