1433d6423SLionel Sambuc /* This file contains the routines related to vnodes.
2433d6423SLionel Sambuc * The entry points are:
3433d6423SLionel Sambuc *
4433d6423SLionel Sambuc * get_vnode - increase counter and get details of an inode
5433d6423SLionel Sambuc * get_free_vnode - get a pointer to a free vnode obj
6433d6423SLionel Sambuc * find_vnode - find a vnode according to the FS endpoint and the inode num.
7433d6423SLionel Sambuc * dup_vnode - duplicate vnode (i.e. increase counter)
8433d6423SLionel Sambuc * put_vnode - drop vnode (i.e. decrease counter)
9433d6423SLionel Sambuc */
10433d6423SLionel Sambuc
11433d6423SLionel Sambuc #include "fs.h"
12433d6423SLionel Sambuc #include "vnode.h"
13433d6423SLionel Sambuc #include "vmnt.h"
14433d6423SLionel Sambuc #include "file.h"
15433d6423SLionel Sambuc #include <minix/vfsif.h>
16433d6423SLionel Sambuc #include <assert.h>
17433d6423SLionel Sambuc
18433d6423SLionel Sambuc /* Is vnode pointer reasonable? */
19433d6423SLionel Sambuc #if NDEBUG
20433d6423SLionel Sambuc #define SANEVP(v)
21433d6423SLionel Sambuc #define CHECKVN(v)
22433d6423SLionel Sambuc #define ASSERTVP(v)
23433d6423SLionel Sambuc #else
24433d6423SLionel Sambuc #define SANEVP(v) ((((v) >= &vnode[0] && (v) < &vnode[NR_VNODES])))
25433d6423SLionel Sambuc
26433d6423SLionel Sambuc #define BADVP(v, f, l) printf("%s:%d: bad vp %p\n", f, l, v)
27433d6423SLionel Sambuc
28433d6423SLionel Sambuc /* vp check that returns 0 for use in check_vrefs() */
29433d6423SLionel Sambuc #define CHECKVN(v) if(!SANEVP(v)) { \
30433d6423SLionel Sambuc BADVP(v, __FILE__, __LINE__); \
31433d6423SLionel Sambuc return 0; \
32433d6423SLionel Sambuc }
33433d6423SLionel Sambuc
34433d6423SLionel Sambuc /* vp check that panics */
35433d6423SLionel Sambuc #define ASSERTVP(v) if(!SANEVP(v)) { \
36433d6423SLionel Sambuc BADVP(v, __FILE__, __LINE__); panic("bad vp"); }
37433d6423SLionel Sambuc #endif
38433d6423SLionel Sambuc
39433d6423SLionel Sambuc #if LOCK_DEBUG
40433d6423SLionel Sambuc /*===========================================================================*
41433d6423SLionel Sambuc * check_vnode_locks_by_me *
42433d6423SLionel Sambuc *===========================================================================*/
check_vnode_locks_by_me(struct fproc * rfp)43433d6423SLionel Sambuc void check_vnode_locks_by_me(struct fproc *rfp)
44433d6423SLionel Sambuc {
45433d6423SLionel Sambuc /* Check whether this thread still has locks held on vnodes */
46433d6423SLionel Sambuc struct vnode *vp;
47433d6423SLionel Sambuc
48433d6423SLionel Sambuc for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++) {
49433d6423SLionel Sambuc if (tll_locked_by_me(&vp->v_lock)) {
50433d6423SLionel Sambuc panic("Thread %d still holds vnode lock on vp %p call_nr=%d\n",
51433d6423SLionel Sambuc mthread_self(), vp, job_call_nr);
52433d6423SLionel Sambuc }
53433d6423SLionel Sambuc }
54433d6423SLionel Sambuc
55433d6423SLionel Sambuc if (rfp->fp_vp_rdlocks != 0)
56433d6423SLionel Sambuc panic("Thread %d still holds read locks on a vnode (%d) call_nr=%d\n",
57433d6423SLionel Sambuc mthread_self(), rfp->fp_vp_rdlocks, job_call_nr);
58433d6423SLionel Sambuc }
59433d6423SLionel Sambuc #endif
60433d6423SLionel Sambuc
61433d6423SLionel Sambuc /*===========================================================================*
62433d6423SLionel Sambuc * check_vnode_locks *
63433d6423SLionel Sambuc *===========================================================================*/
64*a0814afbSRichard Sailer void
check_vnode_locks(void)65*a0814afbSRichard Sailer check_vnode_locks(void)
66433d6423SLionel Sambuc {
67433d6423SLionel Sambuc struct vnode *vp;
68433d6423SLionel Sambuc int count = 0;
69433d6423SLionel Sambuc
70433d6423SLionel Sambuc for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; vp++)
71433d6423SLionel Sambuc if (is_vnode_locked(vp)) {
72433d6423SLionel Sambuc count++;
73433d6423SLionel Sambuc }
74433d6423SLionel Sambuc
75433d6423SLionel Sambuc if (count) panic("%d locked vnodes\n", count);
76433d6423SLionel Sambuc #if 0
77433d6423SLionel Sambuc printf("check_vnode_locks OK\n");
78433d6423SLionel Sambuc #endif
79433d6423SLionel Sambuc }
80433d6423SLionel Sambuc
81433d6423SLionel Sambuc /*===========================================================================*
82433d6423SLionel Sambuc * get_free_vnode *
83433d6423SLionel Sambuc *===========================================================================*/
84*a0814afbSRichard Sailer struct vnode *
get_free_vnode(void)85*a0814afbSRichard Sailer get_free_vnode(void)
86433d6423SLionel Sambuc {
87433d6423SLionel Sambuc /* Find a free vnode slot in the vnode table (it's not actually allocated) */
88433d6423SLionel Sambuc struct vnode *vp;
89433d6423SLionel Sambuc
90433d6423SLionel Sambuc for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) {
91433d6423SLionel Sambuc if (vp->v_ref_count == 0 && !is_vnode_locked(vp)) {
92433d6423SLionel Sambuc vp->v_uid = -1;
93433d6423SLionel Sambuc vp->v_gid = -1;
94433d6423SLionel Sambuc vp->v_sdev = NO_DEV;
95433d6423SLionel Sambuc vp->v_mapfs_e = NONE;
96433d6423SLionel Sambuc vp->v_mapfs_count = 0;
97433d6423SLionel Sambuc vp->v_mapinode_nr = 0;
98433d6423SLionel Sambuc return(vp);
99433d6423SLionel Sambuc }
100433d6423SLionel Sambuc }
101433d6423SLionel Sambuc
102433d6423SLionel Sambuc err_code = ENFILE;
103433d6423SLionel Sambuc return(NULL);
104433d6423SLionel Sambuc }
105433d6423SLionel Sambuc
106433d6423SLionel Sambuc
107433d6423SLionel Sambuc /*===========================================================================*
108433d6423SLionel Sambuc * find_vnode *
109433d6423SLionel Sambuc *===========================================================================*/
find_vnode(int fs_e,ino_t ino)110433d6423SLionel Sambuc struct vnode *find_vnode(int fs_e, ino_t ino)
111433d6423SLionel Sambuc {
112433d6423SLionel Sambuc /* Find a specified (FS endpoint and inode number) vnode in the
113433d6423SLionel Sambuc * vnode table */
114433d6423SLionel Sambuc struct vnode *vp;
115433d6423SLionel Sambuc
116433d6423SLionel Sambuc for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp)
117433d6423SLionel Sambuc if (vp->v_ref_count > 0 && vp->v_inode_nr == ino && vp->v_fs_e == fs_e)
118433d6423SLionel Sambuc return(vp);
119433d6423SLionel Sambuc
120433d6423SLionel Sambuc return(NULL);
121433d6423SLionel Sambuc }
122433d6423SLionel Sambuc
123433d6423SLionel Sambuc /*===========================================================================*
124433d6423SLionel Sambuc * is_vnode_locked *
125433d6423SLionel Sambuc *===========================================================================*/
is_vnode_locked(struct vnode * vp)126433d6423SLionel Sambuc int is_vnode_locked(struct vnode *vp)
127433d6423SLionel Sambuc {
128433d6423SLionel Sambuc /* Find out whether a thread holds a lock on this vnode or is trying to obtain
129433d6423SLionel Sambuc * a lock. */
130433d6423SLionel Sambuc ASSERTVP(vp);
131433d6423SLionel Sambuc
132433d6423SLionel Sambuc return(tll_islocked(&vp->v_lock) || tll_haspendinglock(&vp->v_lock));
133433d6423SLionel Sambuc }
134433d6423SLionel Sambuc
135433d6423SLionel Sambuc /*===========================================================================*
136433d6423SLionel Sambuc * init_vnodes *
137433d6423SLionel Sambuc *===========================================================================*/
init_vnodes(void)138433d6423SLionel Sambuc void init_vnodes(void)
139433d6423SLionel Sambuc {
140433d6423SLionel Sambuc struct vnode *vp;
141433d6423SLionel Sambuc
142433d6423SLionel Sambuc for (vp = &vnode[0]; vp < &vnode[NR_VNODES]; ++vp) {
143433d6423SLionel Sambuc vp->v_fs_e = NONE;
144433d6423SLionel Sambuc vp->v_mapfs_e = NONE;
145433d6423SLionel Sambuc vp->v_inode_nr = 0;
146433d6423SLionel Sambuc vp->v_ref_count = 0;
147433d6423SLionel Sambuc vp->v_fs_count = 0;
148433d6423SLionel Sambuc vp->v_mapfs_count = 0;
149433d6423SLionel Sambuc tll_init(&vp->v_lock);
150433d6423SLionel Sambuc }
151433d6423SLionel Sambuc }
152433d6423SLionel Sambuc
153433d6423SLionel Sambuc /*===========================================================================*
154433d6423SLionel Sambuc * lock_vnode *
155433d6423SLionel Sambuc *===========================================================================*/
lock_vnode(struct vnode * vp,tll_access_t locktype)156433d6423SLionel Sambuc int lock_vnode(struct vnode *vp, tll_access_t locktype)
157433d6423SLionel Sambuc {
158433d6423SLionel Sambuc int r;
159433d6423SLionel Sambuc
160433d6423SLionel Sambuc ASSERTVP(vp);
161433d6423SLionel Sambuc
162433d6423SLionel Sambuc r = tll_lock(&vp->v_lock, locktype);
163433d6423SLionel Sambuc
164433d6423SLionel Sambuc #if LOCK_DEBUG
165433d6423SLionel Sambuc if (locktype == VNODE_READ) {
166433d6423SLionel Sambuc fp->fp_vp_rdlocks++;
167433d6423SLionel Sambuc }
168433d6423SLionel Sambuc #endif
169433d6423SLionel Sambuc
170433d6423SLionel Sambuc if (r == EBUSY) return(r);
171433d6423SLionel Sambuc return(OK);
172433d6423SLionel Sambuc }
173433d6423SLionel Sambuc
174433d6423SLionel Sambuc /*===========================================================================*
175433d6423SLionel Sambuc * unlock_vnode *
176433d6423SLionel Sambuc *===========================================================================*/
unlock_vnode(struct vnode * vp)177433d6423SLionel Sambuc void unlock_vnode(struct vnode *vp)
178433d6423SLionel Sambuc {
179433d6423SLionel Sambuc #if LOCK_DEBUG
180433d6423SLionel Sambuc int i;
181433d6423SLionel Sambuc register struct vnode *rvp;
182433d6423SLionel Sambuc struct worker_thread *w;
183433d6423SLionel Sambuc #endif
184433d6423SLionel Sambuc ASSERTVP(vp);
185433d6423SLionel Sambuc
186433d6423SLionel Sambuc #if LOCK_DEBUG
187433d6423SLionel Sambuc /* Decrease read-only lock counter when not locked as VNODE_OPCL or
188433d6423SLionel Sambuc * VNODE_WRITE */
189433d6423SLionel Sambuc if (!tll_locked_by_me(&vp->v_lock)) {
190433d6423SLionel Sambuc fp->fp_vp_rdlocks--;
191433d6423SLionel Sambuc }
192433d6423SLionel Sambuc
193433d6423SLionel Sambuc for (i = 0; i < NR_VNODES; i++) {
194433d6423SLionel Sambuc rvp = &vnode[i];
195433d6423SLionel Sambuc
196433d6423SLionel Sambuc w = rvp->v_lock.t_write;
197433d6423SLionel Sambuc assert(w != self);
198433d6423SLionel Sambuc while (w && w->w_next != NULL) {
199433d6423SLionel Sambuc w = w->w_next;
200433d6423SLionel Sambuc assert(w != self);
201433d6423SLionel Sambuc }
202433d6423SLionel Sambuc
203433d6423SLionel Sambuc w = rvp->v_lock.t_serial;
204433d6423SLionel Sambuc assert(w != self);
205433d6423SLionel Sambuc while (w && w->w_next != NULL) {
206433d6423SLionel Sambuc w = w->w_next;
207433d6423SLionel Sambuc assert(w != self);
208433d6423SLionel Sambuc }
209433d6423SLionel Sambuc }
210433d6423SLionel Sambuc #endif
211433d6423SLionel Sambuc
212433d6423SLionel Sambuc tll_unlock(&vp->v_lock);
213433d6423SLionel Sambuc }
214433d6423SLionel Sambuc
215433d6423SLionel Sambuc /*===========================================================================*
216433d6423SLionel Sambuc * vnode *
217433d6423SLionel Sambuc *===========================================================================*/
upgrade_vnode_lock(struct vnode * vp)218433d6423SLionel Sambuc void upgrade_vnode_lock(struct vnode *vp)
219433d6423SLionel Sambuc {
220433d6423SLionel Sambuc ASSERTVP(vp);
221433d6423SLionel Sambuc tll_upgrade(&vp->v_lock);
222433d6423SLionel Sambuc }
223433d6423SLionel Sambuc
224433d6423SLionel Sambuc /*===========================================================================*
225433d6423SLionel Sambuc * dup_vnode *
226433d6423SLionel Sambuc *===========================================================================*/
dup_vnode(struct vnode * vp)227433d6423SLionel Sambuc void dup_vnode(struct vnode *vp)
228433d6423SLionel Sambuc {
229433d6423SLionel Sambuc /* dup_vnode() is called to increment the vnode and therefore the
230433d6423SLionel Sambuc * referred inode's counter.
231433d6423SLionel Sambuc */
232433d6423SLionel Sambuc ASSERTVP(vp);
233433d6423SLionel Sambuc vp->v_ref_count++;
234433d6423SLionel Sambuc }
235433d6423SLionel Sambuc
236433d6423SLionel Sambuc
237433d6423SLionel Sambuc /*===========================================================================*
238433d6423SLionel Sambuc * put_vnode *
239433d6423SLionel Sambuc *===========================================================================*/
put_vnode(struct vnode * vp)240433d6423SLionel Sambuc void put_vnode(struct vnode *vp)
241433d6423SLionel Sambuc {
242433d6423SLionel Sambuc /* Decrease vnode's usage counter and decrease inode's usage counter in the
243433d6423SLionel Sambuc * corresponding FS process. Decreasing the fs_count each time we decrease the
244433d6423SLionel Sambuc * ref count would lead to poor performance. Instead, only decrease fs_count
245433d6423SLionel Sambuc * when the ref count hits zero. However, this could lead to fs_count to wrap.
246433d6423SLionel Sambuc * To prevent this, we drop the counter to 1 when the counter hits 256.
247433d6423SLionel Sambuc * We maintain fs_count as a sanity check to make sure VFS and the FS are in
248433d6423SLionel Sambuc * sync.
249433d6423SLionel Sambuc */
250433d6423SLionel Sambuc int r, lock_vp;
251433d6423SLionel Sambuc
252433d6423SLionel Sambuc ASSERTVP(vp);
253433d6423SLionel Sambuc
254433d6423SLionel Sambuc /* Lock vnode. It's quite possible this thread already has a lock on this
255433d6423SLionel Sambuc * vnode. That's no problem, because the reference counter will not decrease
256433d6423SLionel Sambuc * to zero in that case. However, if the counter does decrease to zero *and*
257433d6423SLionel Sambuc * is already locked, we have a consistency problem somewhere. */
258433d6423SLionel Sambuc lock_vp = lock_vnode(vp, VNODE_OPCL);
259433d6423SLionel Sambuc
260433d6423SLionel Sambuc if (vp->v_ref_count > 1) {
261433d6423SLionel Sambuc /* Decrease counter */
262433d6423SLionel Sambuc vp->v_ref_count--;
263433d6423SLionel Sambuc if (vp->v_fs_count > 256)
264433d6423SLionel Sambuc vnode_clean_refs(vp);
265433d6423SLionel Sambuc if (lock_vp != EBUSY) unlock_vnode(vp);
266433d6423SLionel Sambuc return;
267433d6423SLionel Sambuc }
268433d6423SLionel Sambuc
269433d6423SLionel Sambuc /* If we already had a lock, there is a consistency problem */
270433d6423SLionel Sambuc assert(lock_vp != EBUSY);
271433d6423SLionel Sambuc upgrade_vnode_lock(vp); /* Acquire exclusive access */
272433d6423SLionel Sambuc
273433d6423SLionel Sambuc /* A vnode that's not in use can't be put back. */
274433d6423SLionel Sambuc if (vp->v_ref_count <= 0)
275433d6423SLionel Sambuc panic("put_vnode failed: bad v_ref_count %d\n", vp->v_ref_count);
276433d6423SLionel Sambuc
277433d6423SLionel Sambuc /* fs_count should indicate that the file is in use. */
278433d6423SLionel Sambuc if (vp->v_fs_count <= 0)
279433d6423SLionel Sambuc panic("put_vnode failed: bad v_fs_count %d\n", vp->v_fs_count);
280433d6423SLionel Sambuc
281433d6423SLionel Sambuc /* Tell FS we don't need this inode to be open anymore. */
282433d6423SLionel Sambuc r = req_putnode(vp->v_fs_e, vp->v_inode_nr, vp->v_fs_count);
283433d6423SLionel Sambuc
284433d6423SLionel Sambuc if (r != OK) {
285433d6423SLionel Sambuc printf("VFS: putnode failed: %d\n", r);
286433d6423SLionel Sambuc util_stacktrace();
287433d6423SLionel Sambuc }
288433d6423SLionel Sambuc
289433d6423SLionel Sambuc /* This inode could've been mapped. If so, tell mapped FS to close it as
290433d6423SLionel Sambuc * well. If mapped onto same FS, this putnode is not needed. */
291433d6423SLionel Sambuc if (vp->v_mapfs_e != NONE && vp->v_mapfs_e != vp->v_fs_e)
292433d6423SLionel Sambuc req_putnode(vp->v_mapfs_e, vp->v_mapinode_nr, vp->v_mapfs_count);
293433d6423SLionel Sambuc
294433d6423SLionel Sambuc vp->v_fs_count = 0;
295433d6423SLionel Sambuc vp->v_ref_count = 0;
296433d6423SLionel Sambuc vp->v_mapfs_count = 0;
297433d6423SLionel Sambuc
298433d6423SLionel Sambuc unlock_vnode(vp);
299433d6423SLionel Sambuc }
300433d6423SLionel Sambuc
301433d6423SLionel Sambuc
302433d6423SLionel Sambuc /*===========================================================================*
303433d6423SLionel Sambuc * vnode_clean_refs *
304433d6423SLionel Sambuc *===========================================================================*/
vnode_clean_refs(struct vnode * vp)305433d6423SLionel Sambuc void vnode_clean_refs(struct vnode *vp)
306433d6423SLionel Sambuc {
307433d6423SLionel Sambuc /* Tell the underlying FS to drop all reference but one. */
308433d6423SLionel Sambuc
309433d6423SLionel Sambuc if (vp == NULL) return;
310433d6423SLionel Sambuc if (vp->v_fs_count <= 1) return; /* Nothing to do */
311433d6423SLionel Sambuc
312433d6423SLionel Sambuc /* Drop all references except one */
313433d6423SLionel Sambuc req_putnode(vp->v_fs_e, vp->v_inode_nr, vp->v_fs_count - 1);
314433d6423SLionel Sambuc vp->v_fs_count = 1;
315433d6423SLionel Sambuc }
316433d6423SLionel Sambuc
317