Commit 86f996c0 authored by Dave Kleikamp's avatar Dave Kleikamp Committed by Dave Kleikamp

JFS: Handle out of space errors more gracefully

Signed-off-by: default avatarDave Kleikamp <shaggy@austin.ibm.com>
parent b215b03d
...@@ -378,6 +378,8 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot) ...@@ -378,6 +378,8 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
* It's time to move the inline table to an external * It's time to move the inline table to an external
* page and begin to build the xtree * page and begin to build the xtree
*/ */
if (dbAlloc(ip, 0, sbi->nbperpage, &xaddr))
goto clean_up; /* No space */
/* /*
* Save the table, we're going to overwrite it with the * Save the table, we're going to overwrite it with the
...@@ -394,8 +396,8 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot) ...@@ -394,8 +396,8 @@ static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
/* /*
* Allocate the first block & add it to the xtree * Allocate the first block & add it to the xtree
*/ */
xaddr = 0;
if (xtInsert(tid, ip, 0, 0, sbi->nbperpage, &xaddr, 0)) { if (xtInsert(tid, ip, 0, 0, sbi->nbperpage, &xaddr, 0)) {
/* This really shouldn't fail */
jfs_warn("add_index: xtInsert failed!"); jfs_warn("add_index: xtInsert failed!");
memcpy(&jfs_ip->i_dirtable, temp_table, memcpy(&jfs_ip->i_dirtable, temp_table,
sizeof (temp_table)); sizeof (temp_table));
...@@ -975,8 +977,10 @@ static int dtSplitUp(tid_t tid, ...@@ -975,8 +977,10 @@ static int dtSplitUp(tid_t tid,
n -= DTROOTMAXSLOT - sp->header.freecnt; /* header + entries */ n -= DTROOTMAXSLOT - sp->header.freecnt; /* header + entries */
if (n <= split->nslot) if (n <= split->nslot)
xlen++; xlen++;
if ((rc = dbAlloc(ip, 0, (s64) xlen, &xaddr))) if ((rc = dbAlloc(ip, 0, (s64) xlen, &xaddr))) {
DT_PUTPAGE(smp);
goto freeKeyName; goto freeKeyName;
}
pxdlist.maxnpxd = 1; pxdlist.maxnpxd = 1;
pxdlist.npxd = 0; pxdlist.npxd = 0;
......
...@@ -1747,7 +1747,10 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, ...@@ -1747,7 +1747,10 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
if (lwm == next) if (lwm == next)
goto out; goto out;
assert(lwm < next); if (lwm > next) {
jfs_err("xtLog: lwm > next\n");
goto out;
}
tlck->flag |= tlckUPDATEMAP; tlck->flag |= tlckUPDATEMAP;
xadlock->flag = mlckALLOCXADLIST; xadlock->flag = mlckALLOCXADLIST;
xadlock->count = next - lwm; xadlock->count = next - lwm;
...@@ -1913,25 +1916,18 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, ...@@ -1913,25 +1916,18 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
/* /*
* write log records * write log records
*/ */
/* /* log after-image for logredo():
* allocate entries XAD[lwm:next]: *
* logredo() will update bmap for alloc of new/extended
* extents (XAD_NEW|XAD_EXTEND) of XAD[lwm:next) from
* after-image of XADlist;
* logredo() resets (XAD_NEW|XAD_EXTEND) flag when
* applying the after-image to the meta-data page.
*/ */
if (lwm < next) { lrd->type = cpu_to_le16(LOG_REDOPAGE);
/* log after-image for logredo(): PXDaddress(pxd, mp->index);
* logredo() will update bmap for alloc of new/extended PXDlength(pxd, mp->logical_size >> tblk->sb->s_blocksize_bits);
* extents (XAD_NEW|XAD_EXTEND) of XAD[lwm:next) from lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
* after-image of XADlist;
* logredo() resets (XAD_NEW|XAD_EXTEND) flag when
* applying the after-image to the meta-data page.
*/
lrd->type = cpu_to_le16(LOG_REDOPAGE);
PXDaddress(pxd, mp->index);
PXDlength(pxd,
mp->logical_size >> tblk->sb->
s_blocksize_bits);
lrd->backchain =
cpu_to_le32(lmLog(log, tblk, lrd, tlck));
}
/* /*
* truncate entry XAD[twm == next - 1]: * truncate entry XAD[twm == next - 1]:
...@@ -2624,6 +2620,7 @@ void txAbort(tid_t tid, int dirty) ...@@ -2624,6 +2620,7 @@ void txAbort(tid_t tid, int dirty)
lid_t lid, next; lid_t lid, next;
struct metapage *mp; struct metapage *mp;
struct tblock *tblk = tid_to_tblock(tid); struct tblock *tblk = tid_to_tblock(tid);
struct tlock *tlck;
jfs_warn("txAbort: tid:%d dirty:0x%x", tid, dirty); jfs_warn("txAbort: tid:%d dirty:0x%x", tid, dirty);
...@@ -2631,9 +2628,10 @@ void txAbort(tid_t tid, int dirty) ...@@ -2631,9 +2628,10 @@ void txAbort(tid_t tid, int dirty)
* free tlocks of the transaction * free tlocks of the transaction
*/ */
for (lid = tblk->next; lid; lid = next) { for (lid = tblk->next; lid; lid = next) {
next = lid_to_tlock(lid)->next; tlck = lid_to_tlock(lid);
next = tlck->next;
mp = lid_to_tlock(lid)->mp; mp = tlck->mp;
JFS_IP(tlck->ip)->xtlid = 0;
if (mp) { if (mp) {
mp->lid = 0; mp->lid = 0;
......
...@@ -858,7 +858,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, ...@@ -858,7 +858,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
unchar *i_fastsymlink; unchar *i_fastsymlink;
s64 xlen = 0; s64 xlen = 0;
int bmask = 0, xsize; int bmask = 0, xsize;
s64 xaddr; s64 extent = 0, xaddr;
struct metapage *mp; struct metapage *mp;
struct super_block *sb; struct super_block *sb;
struct tblock *tblk; struct tblock *tblk;
...@@ -892,29 +892,11 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, ...@@ -892,29 +892,11 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
down(&JFS_IP(dip)->commit_sem); down(&JFS_IP(dip)->commit_sem);
down(&JFS_IP(ip)->commit_sem); down(&JFS_IP(ip)->commit_sem);
if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE)))
goto out3;
tblk = tid_to_tblock(tid); tblk = tid_to_tblock(tid);
tblk->xflag |= COMMIT_CREATE; tblk->xflag |= COMMIT_CREATE;
tblk->ino = ip->i_ino; tblk->ino = ip->i_ino;
tblk->u.ixpxd = JFS_IP(ip)->ixpxd; tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
/*
* create entry for symbolic link in parent directory
*/
ino = ip->i_ino;
if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
jfs_err("jfs_symlink: dtInsert returned %d", rc);
/* discard ne inode */
goto out3;
}
/* fix symlink access permission /* fix symlink access permission
* (dir_create() ANDs in the u.u_cmask, * (dir_create() ANDs in the u.u_cmask,
* but symlinks really need to be 777 access) * but symlinks really need to be 777 access)
...@@ -922,7 +904,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, ...@@ -922,7 +904,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
ip->i_mode |= 0777; ip->i_mode |= 0777;
/* /*
* write symbolic link target path name * write symbolic link target path name
*/ */
xtInitRoot(tid, ip); xtInitRoot(tid, ip);
...@@ -966,37 +948,48 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, ...@@ -966,37 +948,48 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
xsize = (ssize + bmask) & ~bmask; xsize = (ssize + bmask) & ~bmask;
xaddr = 0; xaddr = 0;
xlen = xsize >> JFS_SBI(sb)->l2bsize; xlen = xsize >> JFS_SBI(sb)->l2bsize;
if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0)) == 0) { if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) {
ip->i_size = ssize - 1; txAbort(tid, 0);
while (ssize) {
int copy_size = min(ssize, PSIZE);
mp = get_metapage(ip, xaddr, PSIZE, 1);
if (mp == NULL) {
dtDelete(tid, dip, &dname, &ino,
JFS_REMOVE);
rc = -EIO;
goto out3;
}
memcpy(mp->data, name, copy_size);
flush_metapage(mp);
#if 0
set_buffer_uptodate(bp);
mark_buffer_dirty(bp, 1);
if (IS_SYNC(dip))
sync_dirty_buffer(bp);
brelse(bp);
#endif /* 0 */
ssize -= copy_size;
xaddr += JFS_SBI(sb)->nbperpage;
}
ip->i_blocks = LBLK2PBLK(sb, xlen);
} else {
dtDelete(tid, dip, &dname, &ino, JFS_REMOVE);
rc = -ENOSPC; rc = -ENOSPC;
goto out3; goto out3;
} }
extent = xaddr;
ip->i_size = ssize - 1;
while (ssize) {
/* This is kind of silly since PATH_MAX == 4K */
int copy_size = min(ssize, PSIZE);
mp = get_metapage(ip, xaddr, PSIZE, 1);
if (mp == NULL) {
dbFree(ip, extent, xlen);
rc = -EIO;
txAbort(tid, 0);
goto out3;
}
memcpy(mp->data, name, copy_size);
flush_metapage(mp);
ssize -= copy_size;
name += copy_size;
xaddr += JFS_SBI(sb)->nbperpage;
}
ip->i_blocks = LBLK2PBLK(sb, xlen);
}
/*
* create entry for symbolic link in parent directory
*/
rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE);
if (rc == 0) {
ino = ip->i_ino;
rc = dtInsert(tid, dip, &dname, &ino, &btstack);
}
if (rc) {
if (xlen)
dbFree(ip, extent, xlen);
txAbort(tid, 0);
/* discard new inode */
goto out3;
} }
insert_inode_hash(ip); insert_inode_hash(ip);
...@@ -1004,23 +997,11 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, ...@@ -1004,23 +997,11 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
/* /*
* commit update of parent directory and link object * commit update of parent directory and link object
*
* if extent allocation failed (ENOSPC),
* the parent inode is committed regardless to avoid
* backing out parent directory update (by dtInsert())
* and subsequent dtDelete() which is harmless wrt
* integrity concern.
* the symlink inode will be freed by iput() at exit
* as it has a zero link count (by dtDelete()) and
* no permanant resources.
*/ */
iplist[0] = dip; iplist[0] = dip;
if (rc == 0) { iplist[1] = ip;
iplist[1] = ip; rc = txCommit(tid, 2, &iplist[0], 0);
rc = txCommit(tid, 2, &iplist[0], 0);
} else
rc = txCommit(tid, 1, &iplist[0], 0);
out3: out3:
txEnd(tid); txEnd(tid);
...@@ -1223,7 +1204,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1223,7 +1204,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
/* Linelock header of dtree */ /* Linelock header of dtree */
tlck = txLock(tid, old_ip, tlck = txLock(tid, old_ip,
(struct metapage *) &JFS_IP(old_ip)->bxflag, (struct metapage *) &JFS_IP(old_ip)->bxflag,
tlckDTREE | tlckBTROOT); tlckDTREE | tlckBTROOT | tlckRELINK);
dtlck = (struct dt_lock *) & tlck->lock; dtlck = (struct dt_lock *) & tlck->lock;
ASSERT(dtlck->index == 0); ASSERT(dtlck->index == 0);
lv = & dtlck->lv[0]; lv = & dtlck->lv[0];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment