xref: /minix3/minix/servers/vfs/vnode.c (revision a0814afb2e128f52ed10c9a5d4c91bf6abc22290)
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