free inode only when noone is holding a pointer to it. should fix open-unlink-

read problem, but untested
This commit is contained in:
kaashoek 2006-08-12 22:03:01 +00:00
parent 14938f9392
commit 22bac2cb9d

79
fs.c
View file

@ -226,6 +226,38 @@ iunlock(struct inode *ip)
release(&inode_table_lock); release(&inode_table_lock);
} }
uint
bmap(struct inode *ip, uint bn)
{
unsigned x;
if(bn >= NDIRECT)
panic("bmap 1");
x = ip->addrs[bn];
if(x == 0)
panic("bmap 2");
return x;
}
void
iunlink(struct inode *ip)
{
int i;
// free inode, its blocks, and remove dir entry
for (i = 0; i < NDIRECT; i++) {
if (ip->addrs[i] != 0) {
bfree(ip->dev, ip->addrs[i]);
ip->addrs[i] = 0;
}
}
ip->size = 0;
ip->major = 0;
ip->minor = 0;
iupdate(ip);
ifree(ip); // is this the right order?
}
// caller is releasing a reference to this inode. // caller is releasing a reference to this inode.
// you must have the inode lock. // you must have the inode lock.
void void
@ -234,6 +266,9 @@ iput(struct inode *ip)
if(ip->count < 1 || ip->busy != 1) if(ip->count < 1 || ip->busy != 1)
panic("iput"); panic("iput");
if ((ip->count <= 1) && (ip->nlink <= 0))
iunlink(ip);
acquire(&inode_table_lock); acquire(&inode_table_lock);
ip->count -= 1; ip->count -= 1;
@ -256,21 +291,6 @@ idecref(struct inode *ip)
release(&inode_table_lock); release(&inode_table_lock);
} }
uint
bmap(struct inode *ip, uint bn)
{
unsigned x;
if(bn >= NDIRECT)
panic("bmap 1");
x = ip->addrs[bn];
if(x == 0)
panic("bmap 2");
return x;
}
#define min(a, b) ((a) < (b) ? (a) : (b))
void void
stati(struct inode *ip, struct stat *st) stati(struct inode *ip, struct stat *st)
{ {
@ -281,6 +301,8 @@ stati(struct inode *ip, struct stat *st)
st->st_size = ip->size; st->st_size = ip->size;
} }
#define min(a, b) ((a) < (b) ? (a) : (b))
int int
readi(struct inode *ip, char *dst, uint off, uint n) readi(struct inode *ip, char *dst, uint off, uint n)
{ {
@ -307,8 +329,6 @@ readi(struct inode *ip, char *dst, uint off, uint n)
return target - n; return target - n;
} }
#define MIN(a, b) ((a < b) ? a : b)
int int
writei(struct inode *ip, char *addr, uint off, uint n) writei(struct inode *ip, char *addr, uint off, uint n)
{ {
@ -330,7 +350,7 @@ writei(struct inode *ip, char *addr, uint off, uint n)
if (b <= 0) return r; if (b <= 0) return r;
ip->addrs[lbn] = b; ip->addrs[lbn] = b;
} }
m = MIN(BSIZE - off % BSIZE, n-r); m = min(BSIZE - off % BSIZE, n-r);
bp = bread(ip->dev, bmap(ip, off / BSIZE)); bp = bread(ip->dev, bmap(ip, off / BSIZE));
memmove (bp->data + off % BSIZE, addr, m); memmove (bp->data + off % BSIZE, addr, m);
bwrite (ip->dev, bp, bmap(ip, off/BSIZE)); bwrite (ip->dev, bp, bmap(ip, off/BSIZE));
@ -476,12 +496,13 @@ mknod(char *cp, short type, short major, short minor)
int int
unlink(char *cp) unlink(char *cp)
{ {
int i; struct inode *ip;
struct inode *ip, *dp; struct inode *dp;
struct dirent *ep = 0; struct dirent *ep = 0;
int off; int off;
struct buf *bp = 0; struct buf *bp = 0;
uint pinum; uint pinum;
if ((ip = namei(cp, &pinum)) == 0) { if ((ip = namei(cp, &pinum)) == 0) {
cprintf("file to be unlinked doesn't exist\n"); cprintf("file to be unlinked doesn't exist\n");
@ -490,24 +511,10 @@ unlink(char *cp)
ip->nlink--; ip->nlink--;
if (ip->nlink > 0) { if (ip->nlink > 0) {
iupdate(ip); iput(ip);
iput(ip); // is this the right order?
return 0; return 0;
} }
// free inode, its blocks, and remove dir entry
for (i = 0; i < NDIRECT; i++) {
if (ip->addrs[i] != 0) {
bfree(ip->dev, ip->addrs[i]);
ip->addrs[i] = 0;
}
}
ip->size = 0;
ip->major = 0;
ip->minor = 0;
iupdate(ip);
ifree(ip); // is this the right order?
dp = iget(rootdev, pinum); dp = iget(rootdev, pinum);
for(off = 0; off < dp->size; off += BSIZE) { for(off = 0; off < dp->size; off += BSIZE) {
bp = bread(dp->dev, bmap(dp, off / BSIZE)); bp = bread(dp->dev, bmap(dp, off / BSIZE));
@ -526,8 +533,8 @@ unlink(char *cp)
ep->inum = 0; ep->inum = 0;
bwrite (dp->dev, bp, bmap(dp, off/BSIZE)); // write directory block bwrite (dp->dev, bp, bmap(dp, off/BSIZE)); // write directory block
brelse(bp); brelse(bp);
iput(ip);
iupdate (dp); iupdate (dp);
iput(dp); iput(dp);
iput(ip);
return 0; return 0;
} }