Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
C
CSEP551
Manage
Activity
Members
Labels
Plan
Issues
0
Issue boards
Milestones
Wiki
Code
Merge requests
0
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Krishna Vinnakota
CSEP551
Commits
38eee5bc
Commit
38eee5bc
authored
13 years ago
by
Robert Morris
Browse files
Options
Downloads
Patches
Plain Diff
more FS comment clarification
parent
a5fbfe41
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
fs.c
+62
-45
62 additions, 45 deletions
fs.c
with
62 additions
and
45 deletions
fs.c
+
62
−
45
View file @
38eee5bc
...
...
@@ -110,41 +110,51 @@ bfree(int dev, uint b)
// to inodes used by multiple processes. The cached
// inodes include book-keeping information that is
// not stored on disk: ip->ref and ip->flags.
//
// ip->ref counts the number of pointer references to this cached
// inode; references are typically kept in struct file and in proc->cwd.
// When ip->ref falls to zero, the inode is no longer cached.
// It is an error to use an inode without holding a reference to it.
//
// Processes are only allowed to read and write inode
// metadata and contents when holding the inode's lock,
// represented by the I_BUSY bit in ip->flags.
// Because inode locks are held during disk accesses,
// they are implemented using a flag rather than with
// spin locks. ilock() and iunlock() manipulate an
// inode's I_BUSY flag. Many routines in this file expect
// the caller to have already locked the inode; leaving
// this responsibility with the caller makes it possible for them
// to create arbitrarily-sized atomic operations.
// An inode and its in-memory represtative go through a
// sequence of states before they can be used by the
// rest of the file system code.
//
// To give maximum control over locking to the callers,
// the routines in this file that return inode pointers
// return pointers to *unlocked* inodes. It is the callers'
// responsibility to lock them before using them. A non-zero
// ip->ref keeps these unlocked inodes in the cache.
// * Allocation: an inode is allocated if its type (on disk)
// is non-zero. ialloc() allocates, iput() frees if
// the link count has fallen to zero.
//
// In order for the file system code to look at an inode, the inode
// must pass through a number of states, with transitions
// driven by the indicated functions:
//
// * Allocated on disk, indicated by a non-zero type.
// ialloc() and iput().
// * Referenced in the cache, indicated by ip->ref > 0.
// iget() and iput().
// * Cached inode is valid, indicated by I_VALID.
// ilock() and iput().
// * Locked, indicated by I_BUSY.
// ilock() and iunlock().
// * Referencing in cache: an entry in the inode cache
// is free if ip->ref is zero. Otherwise ip->ref tracks
// the number of in-memory pointers to the entry (open
// files and current directories). iget() to find or
// create a cache entry and increment its ref, iput()
// to decrement ref.
//
// * Valid: the information (type, size, &c) in an inode
// cache entry is only correct when the I_VALID bit
// is set in ip->flags. ilock() reads the inode from
// the disk and sets I_VALID, while iput() clears
// I_VALID if ip->ref has fallen to zero.
//
// * Locked: file system code may only examine and modify
// the information in an inode and its content if it
// has first locked the inode. The I_BUSY flag indicates
// that the inode is locked. ilock() sets I_BUSY,
// while iunlock clears it.
//
// Thus a typical sequence is:
// ip = iget(dev, inum)
// ilock(ip)
// ... examine and modify ip->xxx ...
// iunlock(ip)
// iput(ip)
//
// ilock() is separate from iget() so that system calls can
// get a long-term reference to an inode (as for an open file)
// and only lock it for short periods (e.g., in read()).
// The separation also helps avoid deadlock and races during
// pathname lookup. iget() increments ip->ref so that the inode
// stays cached and pointers to it remain valid.
//
// Many internal file system functions expect the caller to
// have locked the inodes involved; this lets callers create
// multi-step atomic operations.
struct
{
struct
spinlock
lock
;
...
...
@@ -187,7 +197,7 @@ ialloc(uint dev, short type)
panic
(
"ialloc: no inodes"
);
}
// Copy
inode, which has changed, from memory
to disk.
// Copy
a modified in-memory inode
to disk.
void
iupdate
(
struct
inode
*
ip
)
{
...
...
@@ -207,7 +217,8 @@ iupdate(struct inode *ip)
}
// Find the inode with number inum on device dev
// and return the in-memory copy.
// and return the in-memory copy. Does not lock
// the inode and does not read it from disk.
static
struct
inode
*
iget
(
uint
dev
,
uint
inum
)
{
...
...
@@ -215,7 +226,7 @@ iget(uint dev, uint inum)
acquire
(
&
icache
.
lock
);
//
Try for cached inode.
//
Is the inode already cached?
empty
=
0
;
for
(
ip
=
&
icache
.
inode
[
0
];
ip
<
&
icache
.
inode
[
NINODE
];
ip
++
){
if
(
ip
->
ref
>
0
&&
ip
->
dev
==
dev
&&
ip
->
inum
==
inum
){
...
...
@@ -227,7 +238,7 @@ iget(uint dev, uint inum)
empty
=
ip
;
}
//
Allocate fresh inode
.
//
Recycle an inode cache entry
.
if
(
empty
==
0
)
panic
(
"iget: no inodes"
);
...
...
@@ -253,6 +264,7 @@ idup(struct inode *ip)
}
// Lock the given inode.
// Reads the inode from disk if necessary.
void
ilock
(
struct
inode
*
ip
)
{
...
...
@@ -297,13 +309,17 @@ iunlock(struct inode *ip)
release
(
&
icache
.
lock
);
}
// Caller holds reference to unlocked ip. Drop reference.
// Drop a reference to an in-memory inode.
// If that was the last reference, the inode cache entry can
// be recycled.
// If that was the last reference and the inode has no links
// to it, free the inode (and its content) on disk.
void
iput
(
struct
inode
*
ip
)
{
acquire
(
&
icache
.
lock
);
if
(
ip
->
ref
==
1
&&
(
ip
->
flags
&
I_VALID
)
&&
ip
->
nlink
==
0
){
// inode
i
s no l
onger used
: truncate and free inode.
// inode
ha
s no l
inks
: truncate and free inode.
if
(
ip
->
flags
&
I_BUSY
)
panic
(
"iput busy"
);
ip
->
flags
|=
I_BUSY
;
...
...
@@ -328,12 +344,12 @@ iunlockput(struct inode *ip)
}
//PAGEBREAK!
// Inode content
s
// Inode content
//
// The content
s
(data) associated with each inode is stored
// in
a sequence of
blocks on the disk.
The first NDIRECT blocks
// The content (data) associated with each inode is stored
// in blocks on the disk. The first NDIRECT block
number
s
// are listed in ip->addrs[]. The next NINDIRECT blocks are
// listed in
the
block ip->addrs[NDIRECT].
// listed in block ip->addrs[NDIRECT].
// Return the disk block address of the nth block in inode ip.
// If there is no such block, bmap allocates one.
...
...
@@ -368,8 +384,10 @@ bmap(struct inode *ip, uint bn)
}
// Truncate inode (discard contents).
// Only called after the last dirent referring
// to this inode has been erased on disk.
// Only called when the inode has no links
// to it (no directory entries referring to it)
// and has no in-memory reference to it (is
// not an open file or current directory).
static
void
itrunc
(
struct
inode
*
ip
)
{
...
...
@@ -484,7 +502,6 @@ namecmp(const char *s, const char *t)
// Look for a directory entry in a directory.
// If found, set *poff to byte offset of entry.
// Caller must have already locked dp.
struct
inode
*
dirlookup
(
struct
inode
*
dp
,
char
*
name
,
uint
*
poff
)
{
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment