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