[PATCH] Handle out of space errors more gracefully (1 of 2)

[email protected] Thu, 10 Jun 2004 12:41:53 -0500
Newsgroups gmane.comp.file-systems.jfs.patches
Message-ID <[email protected]>
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/06/02 16:28:51-05:00 [email protected] 
#   JFS: Handle out of space errors more gracefully
#   
#   Signed-off-by: Dave Kleikamp <[email protected]>
# 
diff -Nru a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
--- a/fs/jfs/jfs_dtree.c	2004-06-10 12:37:17 -05:00
+++ b/fs/jfs/jfs_dtree.c	2004-06-10 12:37:17 -05:00
@@ -378,6 +378,8 @@
 		 * It's time to move the inline table to an external
 		 * 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
@@ -394,8 +396,8 @@
 		/*
 		 * Allocate the first block & add it to the xtree
 		 */
-		xaddr = 0;
 		if (xtInsert(tid, ip, 0, 0, sbi->nbperpage, &xaddr, 0)) {
+			/* This really shouldn't fail */
 			jfs_warn("add_index: xtInsert failed!");
 			memcpy(&jfs_ip->i_dirtable, temp_table,
 			       sizeof (temp_table));
@@ -975,8 +977,10 @@
 		n -= DTROOTMAXSLOT - sp->header.freecnt; /* header + entries */
 		if (n <= split->nslot)
 			xlen++;
-		if ((rc = dbAlloc(ip, 0, (s64) xlen, &xaddr)))
+		if ((rc = dbAlloc(ip, 0, (s64) xlen, &xaddr))) {
+			DT_PUTPAGE(smp);
 			goto freeKeyName;
+		}
 
 		pxdlist.maxnpxd = 1;
 		pxdlist.npxd = 0;
diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c	2004-06-10 12:37:17 -05:00
+++ b/fs/jfs/jfs_txnmgr.c	2004-06-10 12:37:17 -05:00
@@ -1747,7 +1747,10 @@
 
 		if (lwm == next)
 			goto out;
-		assert(lwm < next);
+		if (lwm > next) {
+			jfs_err("xtLog: lwm > next\n");
+			goto out;
+		}
 		tlck->flag |= tlckUPDATEMAP;
 		xadlock->flag = mlckALLOCXADLIST;
 		xadlock->count = next - lwm;
@@ -1913,25 +1916,18 @@
 		/*
 		 *      write log records
 		 */
-		/*
-		 * allocate entries XAD[lwm:next]:
-		 */
-		if (lwm < next) {
-			/* log after-image for logredo():
-			 * 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.
-			 */
-			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));
-		}
+		/* log after-image for logredo():
+		 *
+		 * 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.
+		 */
+		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]:
@@ -2624,6 +2620,7 @@
 	lid_t lid, next;
 	struct metapage *mp;
 	struct tblock *tblk = tid_to_tblock(tid);
+	struct tlock *tlck;
 
 	jfs_warn("txAbort: tid:%d dirty:0x%x", tid, dirty);
 
@@ -2631,9 +2628,10 @@
 	 * free tlocks of the transaction
 	 */
 	for (lid = tblk->next; lid; lid = next) {
-		next = lid_to_tlock(lid)->next;
-
-		mp = lid_to_tlock(lid)->mp;
+		tlck = lid_to_tlock(lid);
+		next = tlck->next;
+		mp = tlck->mp;
+		JFS_IP(tlck->ip)->xtlid = 0;
 
 		if (mp) {
 			mp->lid = 0;
diff -Nru a/fs/jfs/namei.c b/fs/jfs/namei.c
--- a/fs/jfs/namei.c	2004-06-10 12:37:17 -05:00
+++ b/fs/jfs/namei.c	2004-06-10 12:37:17 -05:00
@@ -858,7 +858,7 @@
 	unchar *i_fastsymlink;
 	s64 xlen = 0;
 	int bmask = 0, xsize;
-	s64 xaddr;
+	s64 extent = 0, xaddr;
 	struct metapage *mp;
 	struct super_block *sb;
 	struct tblock *tblk;
@@ -892,29 +892,11 @@
 	down(&JFS_IP(dip)->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->xflag |= COMMIT_CREATE;
 	tblk->ino = ip->i_ino;
 	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
 	 * (dir_create() ANDs in the u.u_cmask, 
 	 * but symlinks really need to be 777 access)
@@ -922,7 +904,7 @@
 	ip->i_mode |= 0777;
 
 	/*
-	   *       write symbolic link target path name
+	 * write symbolic link target path name
 	 */
 	xtInitRoot(tid, ip);
 
@@ -966,37 +948,48 @@
 		xsize = (ssize + bmask) & ~bmask;
 		xaddr = 0;
 		xlen = xsize >> JFS_SBI(sb)->l2bsize;
-		if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0)) == 0) {
-			ip->i_size = ssize - 1;
-			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);
+		if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) {
+			txAbort(tid, 0);
 			rc = -ENOSPC;
 			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);
@@ -1004,23 +997,11 @@
 
 	/*
 	 * 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;
-	if (rc == 0) {
-		iplist[1] = ip;
-		rc = txCommit(tid, 2, &iplist[0], 0);
-	} else
-		rc = txCommit(tid, 1, &iplist[0], 0);
+	iplist[1] = ip;
+	rc = txCommit(tid, 2, &iplist[0], 0);
 
       out3:
 	txEnd(tid);
@@ -1223,7 +1204,7 @@
 			/* Linelock header of dtree */
 			tlck = txLock(tid, old_ip,
 				    (struct metapage *) &JFS_IP(old_ip)->bxflag,
-				      tlckDTREE | tlckBTROOT);
+				      tlckDTREE | tlckBTROOT | tlckRELINK);
 			dtlck = (struct dt_lock *) & tlck->lock;
 			ASSERT(dtlck->index == 0);
 			lv = & dtlck->lv[0];