@@ -110,41 +110,51 @@ bfree(int dev, uint b)
110110// to inodes used by multiple processes. The cached
111111// inodes include book-keeping information that is
112112// not stored on disk: ip->ref and ip->flags.
113- //
114- // ip->ref counts the number of pointer references to this cached
115- // inode; references are typically kept in struct file and in proc->cwd.
116- // When ip->ref falls to zero, the inode is no longer cached.
117- // It is an error to use an inode without holding a reference to it.
118113//
119- // Processes are only allowed to read and write inode
120- // metadata and contents when holding the inode's lock,
121- // represented by the I_BUSY bit in ip->flags.
122- // Because inode locks are held during disk accesses,
123- // they are implemented using a flag rather than with
124- // spin locks. ilock() and iunlock() manipulate an
125- // inode's I_BUSY flag. Many routines in this file expect
126- // the caller to have already locked the inode; leaving
127- // this responsibility with the caller makes it possible for them
128- // to create arbitrarily-sized atomic operations.
114+ // An inode and its in-memory represtative go through a
115+ // sequence of states before they can be used by the
116+ // rest of the file system code.
129117//
130- // To give maximum control over locking to the callers,
131- // the routines in this file that return inode pointers
132- // return pointers to *unlocked* inodes. It is the callers'
133- // responsibility to lock them before using them. A non-zero
134- // ip->ref keeps these unlocked inodes in the cache.
118+ // * Allocation: an inode is allocated if its type (on disk)
119+ // is non-zero. ialloc() allocates, iput() frees if
120+ // the link count has fallen to zero.
135121//
136- // In order for the file system code to look at an inode, the inode
137- // must pass through a number of states, with transitions
138- // driven by the indicated functions:
139- //
140- // * Allocated on disk, indicated by a non-zero type.
141- // ialloc() and iput().
142- // * Referenced in the cache, indicated by ip->ref > 0.
143- // iget() and iput().
144- // * Cached inode is valid, indicated by I_VALID.
145- // ilock() and iput().
146- // * Locked, indicated by I_BUSY.
147- // ilock() and iunlock().
122+ // * Referencing in cache: an entry in the inode cache
123+ // is free if ip->ref is zero. Otherwise ip->ref tracks
124+ // the number of in-memory pointers to the entry (open
125+ // files and current directories). iget() to find or
126+ // create a cache entry and increment its ref, iput()
127+ // to decrement ref.
128+ //
129+ // * Valid: the information (type, size, &c) in an inode
130+ // cache entry is only correct when the I_VALID bit
131+ // is set in ip->flags. ilock() reads the inode from
132+ // the disk and sets I_VALID, while iput() clears
133+ // I_VALID if ip->ref has fallen to zero.
134+ //
135+ // * Locked: file system code may only examine and modify
136+ // the information in an inode and its content if it
137+ // has first locked the inode. The I_BUSY flag indicates
138+ // that the inode is locked. ilock() sets I_BUSY,
139+ // while iunlock clears it.
140+ //
141+ // Thus a typical sequence is:
142+ // ip = iget(dev, inum)
143+ // ilock(ip)
144+ // ... examine and modify ip->xxx ...
145+ // iunlock(ip)
146+ // iput(ip)
147+ //
148+ // ilock() is separate from iget() so that system calls can
149+ // get a long-term reference to an inode (as for an open file)
150+ // and only lock it for short periods (e.g., in read()).
151+ // The separation also helps avoid deadlock and races during
152+ // pathname lookup. iget() increments ip->ref so that the inode
153+ // stays cached and pointers to it remain valid.
154+ //
155+ // Many internal file system functions expect the caller to
156+ // have locked the inodes involved; this lets callers create
157+ // multi-step atomic operations.
148158
149159struct {
150160 struct spinlock lock ;
@@ -187,7 +197,7 @@ ialloc(uint dev, short type)
187197 panic ("ialloc: no inodes" );
188198}
189199
190- // Copy inode, which has changed, from memory to disk.
200+ // Copy a modified in- memory inode to disk.
191201void
192202iupdate (struct inode * ip )
193203{
@@ -207,15 +217,16 @@ iupdate(struct inode *ip)
207217}
208218
209219// Find the inode with number inum on device dev
210- // and return the in-memory copy.
220+ // and return the in-memory copy. Does not lock
221+ // the inode and does not read it from disk.
211222static struct inode *
212223iget (uint dev , uint inum )
213224{
214225 struct inode * ip , * empty ;
215226
216227 acquire (& icache .lock );
217228
218- // Try for cached inode.
229+ // Is the inode already cached?
219230 empty = 0 ;
220231 for (ip = & icache .inode [0 ]; ip < & icache .inode [NINODE ]; ip ++ ){
221232 if (ip -> ref > 0 && ip -> dev == dev && ip -> inum == inum ){
@@ -227,7 +238,7 @@ iget(uint dev, uint inum)
227238 empty = ip ;
228239 }
229240
230- // Allocate fresh inode.
241+ // Recycle an inode cache entry .
231242 if (empty == 0 )
232243 panic ("iget: no inodes" );
233244
@@ -253,6 +264,7 @@ idup(struct inode *ip)
253264}
254265
255266// Lock the given inode.
267+ // Reads the inode from disk if necessary.
256268void
257269ilock (struct inode * ip )
258270{
@@ -297,13 +309,17 @@ iunlock(struct inode *ip)
297309 release (& icache .lock );
298310}
299311
300- // Caller holds reference to unlocked ip. Drop reference.
312+ // Drop a reference to an in-memory inode.
313+ // If that was the last reference, the inode cache entry can
314+ // be recycled.
315+ // If that was the last reference and the inode has no links
316+ // to it, free the inode (and its content) on disk.
301317void
302318iput (struct inode * ip )
303319{
304320 acquire (& icache .lock );
305321 if (ip -> ref == 1 && (ip -> flags & I_VALID ) && ip -> nlink == 0 ){
306- // inode is no longer used : truncate and free inode.
322+ // inode has no links : truncate and free inode.
307323 if (ip -> flags & I_BUSY )
308324 panic ("iput busy" );
309325 ip -> flags |= I_BUSY ;
@@ -328,12 +344,12 @@ iunlockput(struct inode *ip)
328344}
329345
330346//PAGEBREAK!
331- // Inode contents
347+ // Inode content
332348//
333- // The contents (data) associated with each inode is stored
334- // in a sequence of blocks on the disk. The first NDIRECT blocks
349+ // The content (data) associated with each inode is stored
350+ // in blocks on the disk. The first NDIRECT block numbers
335351// are listed in ip->addrs[]. The next NINDIRECT blocks are
336- // listed in the block ip->addrs[NDIRECT].
352+ // listed in block ip->addrs[NDIRECT].
337353
338354// Return the disk block address of the nth block in inode ip.
339355// If there is no such block, bmap allocates one.
@@ -368,8 +384,10 @@ bmap(struct inode *ip, uint bn)
368384}
369385
370386// Truncate inode (discard contents).
371- // Only called after the last dirent referring
372- // to this inode has been erased on disk.
387+ // Only called when the inode has no links
388+ // to it (no directory entries referring to it)
389+ // and has no in-memory reference to it (is
390+ // not an open file or current directory).
373391static void
374392itrunc (struct inode * ip )
375393{
@@ -484,7 +502,6 @@ namecmp(const char *s, const char *t)
484502
485503// Look for a directory entry in a directory.
486504// If found, set *poff to byte offset of entry.
487- // Caller must have already locked dp.
488505struct inode *
489506dirlookup (struct inode * dp , char * name , uint * poff )
490507{
0 commit comments