tolerate running out of disk blocks

This commit is contained in:
Robert Morris 2022-08-10 06:13:52 -04:00
parent 7d573bae2a
commit 872fa88e8a
2 changed files with 76 additions and 12 deletions

View file

@ -61,6 +61,7 @@ bzero(int dev, int bno)
// Blocks. // Blocks.
// Allocate a zeroed disk block. // Allocate a zeroed disk block.
// returns 0 if out of disk space.
static uint static uint
balloc(uint dev) balloc(uint dev)
{ {
@ -82,7 +83,8 @@ balloc(uint dev)
} }
brelse(bp); brelse(bp);
} }
panic("balloc: out of blocks"); printf("balloc: out of blocks\n");
return 0;
} }
// Free a disk block. // Free a disk block.
@ -109,8 +111,8 @@ bfree(int dev, uint b)
// its size, the number of links referring to it, and the // its size, the number of links referring to it, and the
// list of blocks holding the file's content. // list of blocks holding the file's content.
// //
// The inodes are laid out sequentially on disk at // The inodes are laid out sequentially on disk at block
// sb.startinode. Each inode has a number, indicating its // sb.inodestart. Each inode has a number, indicating its
// position on the disk. // position on the disk.
// //
// The kernel keeps a table of in-use inodes in memory // The kernel keeps a table of in-use inodes in memory
@ -374,6 +376,7 @@ iunlockput(struct inode *ip)
// Return the disk block address of the nth block in inode ip. // Return the disk block address of the nth block in inode ip.
// If there is no such block, bmap allocates one. // If there is no such block, bmap allocates one.
// returns 0 if out of disk space.
static uint static uint
bmap(struct inode *ip, uint bn) bmap(struct inode *ip, uint bn)
{ {
@ -381,22 +384,33 @@ bmap(struct inode *ip, uint bn)
struct buf *bp; struct buf *bp;
if(bn < NDIRECT){ if(bn < NDIRECT){
if((addr = ip->addrs[bn]) == 0) if((addr = ip->addrs[bn]) == 0){
ip->addrs[bn] = addr = balloc(ip->dev); addr = balloc(ip->dev);
if(addr == 0)
return 0;
ip->addrs[bn] = addr;
}
return addr; return addr;
} }
bn -= NDIRECT; bn -= NDIRECT;
if(bn < NINDIRECT){ if(bn < NINDIRECT){
// Load indirect block, allocating if necessary. // Load indirect block, allocating if necessary.
if((addr = ip->addrs[NDIRECT]) == 0) if((addr = ip->addrs[NDIRECT]) == 0){
ip->addrs[NDIRECT] = addr = balloc(ip->dev); addr = balloc(ip->dev);
if(addr == 0)
return 0;
ip->addrs[NDIRECT] = addr;
}
bp = bread(ip->dev, addr); bp = bread(ip->dev, addr);
a = (uint*)bp->data; a = (uint*)bp->data;
if((addr = a[bn]) == 0){ if((addr = a[bn]) == 0){
a[bn] = addr = balloc(ip->dev); addr = balloc(ip->dev);
if(addr){
a[bn] = addr;
log_write(bp); log_write(bp);
} }
}
brelse(bp); brelse(bp);
return addr; return addr;
} }
@ -464,7 +478,10 @@ readi(struct inode *ip, int user_dst, uint64 dst, uint off, uint n)
n = ip->size - off; n = ip->size - off;
for(tot=0; tot<n; tot+=m, off+=m, dst+=m){ for(tot=0; tot<n; tot+=m, off+=m, dst+=m){
bp = bread(ip->dev, bmap(ip, off/BSIZE)); uint addr = bmap(ip, off/BSIZE);
if(addr == 0)
break;
bp = bread(ip->dev, addr);
m = min(n - tot, BSIZE - off%BSIZE); m = min(n - tot, BSIZE - off%BSIZE);
if(either_copyout(user_dst, dst, bp->data + (off % BSIZE), m) == -1) { if(either_copyout(user_dst, dst, bp->data + (off % BSIZE), m) == -1) {
brelse(bp); brelse(bp);
@ -495,7 +512,10 @@ writei(struct inode *ip, int user_src, uint64 src, uint off, uint n)
return -1; return -1;
for(tot=0; tot<n; tot+=m, off+=m, src+=m){ for(tot=0; tot<n; tot+=m, off+=m, src+=m){
bp = bread(ip->dev, bmap(ip, off/BSIZE)); uint addr = bmap(ip, off/BSIZE);
if(addr == 0)
break;
bp = bread(ip->dev, addr);
m = min(n - tot, BSIZE - off%BSIZE); m = min(n - tot, BSIZE - off%BSIZE);
if(either_copyin(bp->data + (off % BSIZE), user_src, src, m) == -1) { if(either_copyin(bp->data + (off % BSIZE), user_src, src, m) == -1) {
brelse(bp); brelse(bp);

View file

@ -2706,6 +2706,49 @@ execout(char *s)
exit(0); exit(0);
} }
// can the kernel tolerate running out of disk space?
void
diskfull(char *s)
{
int fi;
int done = 0;
for(fi = 0; done == 0; fi++){
char name[32];
name[0] = 'b';
name[1] = 'i';
name[2] = 'g';
name[3] = '0' + fi;
name[4] = '\0';
unlink(name);
int fd = open(name, O_CREATE|O_RDWR|O_TRUNC);
if(fd < 0){
printf("%s: could not create file %s\n", s, name);
done = 1;
break;
}
for(int i = 0; i < MAXFILE; i++){
char buf[BSIZE];
if(write(fd, buf, BSIZE) != BSIZE){
done = 1;
close(fd);
break;
}
}
close(fd);
}
for(int i = 0; i < fi; i++){
char name[32];
name[0] = 'b';
name[1] = 'i';
name[2] = 'g';
name[3] = '0' + i;
name[4] = '\0';
unlink(name);
}
}
// //
// use sbrk() to count how many free physical memory pages there are. // use sbrk() to count how many free physical memory pages there are.
// touches the pages to force allocation. // touches the pages to force allocation.
@ -2818,7 +2861,7 @@ main(int argc, char *argv[])
void (*f)(char *); void (*f)(char *);
char *s; char *s;
} tests[] = { } tests[] = {
{MAXVAplus, "MAXVAplus"}, {diskfull, "diskfull"},
{manywrites, "manywrites"}, {manywrites, "manywrites"},
{execout, "execout"}, {execout, "execout"},
{copyin, "copyin"}, {copyin, "copyin"},
@ -2880,6 +2923,7 @@ main(int argc, char *argv[])
{dirfile, "dirfile"}, {dirfile, "dirfile"},
{iref, "iref"}, {iref, "iref"},
{forktest, "forktest"}, {forktest, "forktest"},
{MAXVAplus, "MAXVAplus"},
{bigdir, "bigdir"}, // slow {bigdir, "bigdir"}, // slow
{ 0, 0}, { 0, 0},
}; };