http://jfs.bkbits.net/linux-2.5
shaggy@austin.ibm.com|ChangeSet|20040712183138|07615 shaggy

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/07/12 21:11:35-07:00 akpm@bix.(none) 
#   Merge http://jfs.bkbits.net/linux-2.5 into bix.(none):/usr/src/bk-jfs
# 
# fs/jfs/super.c
#   2004/07/12 21:11:32-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# fs/jfs/jfs_xtree.c
#   2004/07/12 21:11:32-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# fs/jfs/jfs_metapage.c
#   2004/07/12 21:11:32-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# fs/jfs/jfs_imap.c
#   2004/07/12 21:11:32-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/12 13:31:38-05:00 shaggy@austin.ibm.com 
#   JFS: Add d_hash and d_compare operations for case-insensitive names
#   
#   JFS supports OS/2-compatibility with case-insensitive file names.
#   To avoid multiple dentries for these names, jfs needs to provide
#   the d_hash and d_compare dentry_operations.  The operations are
#   only used when the volume was created in OS/2 or with the -O flag.
# 
# fs/jfs/super.c
#   2004/07/12 13:31:12-05:00 shaggy@austin.ibm.com +5 -0
#   Add d_hash and d_compare dentry_operations for case-insensitive names
# 
# fs/jfs/namei.c
#   2004/07/12 13:31:12-05:00 shaggy@austin.ibm.com +55 -2
#   Add d_hash and d_compare dentry_operations for case-insensitive names
# 
# ChangeSet
#   2004/07/12 06:36:31-07:00 jfs.adm@hostme.bitkeeper.com 
#   Merge bk://linux.bkbits.net/linux-2.5
#   into hostme.bitkeeper.com:/repos/j/jfs/linux-2.5
# 
# fs/jfs/super.c
#   2004/07/12 06:36:25-07:00 jfs.adm@hostme.bitkeeper.com +0 -0
#   Auto merged
# 
# fs/jfs/jfs_xtree.c
#   2004/07/12 06:36:25-07:00 jfs.adm@hostme.bitkeeper.com +0 -0
#   Auto merged
# 
# fs/jfs/jfs_metapage.c
#   2004/07/12 06:36:25-07:00 jfs.adm@hostme.bitkeeper.com +0 -0
#   Auto merged
# 
# fs/jfs/jfs_imap.c
#   2004/07/12 06:36:25-07:00 jfs.adm@hostme.bitkeeper.com +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/11 13:34:53-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-jfs
# 
# fs/jfs/super.c
#   2004/07/11 13:34:49-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# fs/jfs/jfs_xtree.c
#   2004/07/11 13:34:49-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# fs/jfs/jfs_metapage.c
#   2004/07/11 13:34:49-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# fs/jfs/jfs_imap.c
#   2004/07/11 13:34:49-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/07/09 07:40:34-05:00 shaggy@austin.ibm.com 
#   JFS: jfs_dmap build fix
#   
#   fs/jfs/jfs_dmap.c: In function `dbAllocNear':
#   fs/jfs/jfs_dmap.c:1343: parse error before `*'
#   fs/jfs/jfs_dmap.c:1357: `leaf' undeclared (first use in this function)
#   fs/jfs/jfs_dmap.c:1357: (Each undeclared identifier is reported only once
#   fs/jfs/jfs_dmap.c:1357: for each function it appears in.)
#   
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
# 
# fs/jfs/jfs_dmap.c
#   2004/07/09 07:40:16-05:00 shaggy@austin.ibm.com +2 -1
#   build fix
# 
# ChangeSet
#   2004/07/07 16:04:45-05:00 shaggy@austin.ibm.com 
#   JFS: Check for dmap corruption before using leafidx
#   
#   Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
# 
# fs/jfs/jfs_dmap.c
#   2004/07/07 16:04:26-05:00 shaggy@austin.ibm.com +34 -0
#   Check for dmap corruption before using leafidx
# 
# ChangeSet
#   2004/07/07 15:56:52-05:00 shaggy@austin.ibm.com 
#   JFS: prevent concurrent calls to txCommit on the imap inode
#   
#   Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
# 
# fs/jfs/jfs_imap.c
#   2004/07/07 15:56:10-05:00 shaggy@austin.ibm.com +6 -0
#   Don't allow diFree & diNewIAG to call txCommit at the same time
# 
# ChangeSet
#   2004/07/07 15:34:11-05:00 shaggy@austin.ibm.com 
#   JFS: Protect active_ag with a spinlock
#   
#   Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
# 
# fs/jfs/super.c
#   2004/07/07 15:33:27-05:00 shaggy@austin.ibm.com +4 -0
#   protect active_ag with a spinlock
# 
# fs/jfs/jfs_incore.h
#   2004/07/07 15:33:27-05:00 shaggy@austin.ibm.com +1 -0
#   protect active_ag with a spinlock
# 
# fs/jfs/jfs_extent.c
#   2004/07/07 15:33:27-05:00 shaggy@austin.ibm.com +2 -0
#   protect active_ag with a spinlock
# 
# fs/jfs/file.c
#   2004/07/07 15:33:27-05:00 shaggy@austin.ibm.com +4 -0
#   protect active_ag with a spinlock
# 
# ChangeSet
#   2004/07/06 08:31:31-05:00 shaggy@austin.ibm.com 
#   JFS: Updated field isn't always written to disk during truncate
#   
#   There is a possibility that a change to header.next is not logged
#   or written to disk if it is the only change to an xtree leaf page.
#   
#   Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
# 
# fs/jfs/jfs_xtree.c
#   2004/07/06 08:31:13-05:00 shaggy@austin.ibm.com +11 -1
#   Make sure header.next change is logged & written
# 
# ChangeSet
#   2004/06/30 15:41:40-05:00 shaggy@austin.ibm.com 
#   JFS: Error path released metadata page it shouldn't have
#   
#   Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
# 
# fs/jfs/jfs_xtree.c
#   2004/06/30 15:41:20-05:00 shaggy@austin.ibm.com +8 -17
#   Remove extra XT_PUTPAGE(rcmp) on err path
# 
# ChangeSet
#   2004/06/14 15:19:58-05:00 shaggy@austin.ibm.com 
#   JFS: Don't allow reading beyond the inode map's EOF
#   
#   If we try to read inodes that are beyond the size of the inode map,
#   __read_metapages would read unitialized pages into the inode map's
#   address space.  If the inode map is later grown in order to allocate
#   more inodes, the page is initialized and written under a different
#   address space.  Having the stale page in the page cache prevents the
#   properly initialized page from being read, and results in errors.
#   
#   This problem can be provoked by an nfs client trying to read an inode
#   that does not exist.
#   
#   Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
# 
# fs/jfs/jfs_metapage.c
#   2004/06/14 15:19:21-05:00 shaggy@austin.ibm.com +9 -1
#   Don't allow reading pages outside of imap
# 
diff -Nru a/fs/jfs/file.c b/fs/jfs/file.c
--- a/fs/jfs/file.c	2004-07-13 12:42:31 -07:00
+++ b/fs/jfs/file.c	2004-07-13 12:42:31 -07:00
@@ -65,11 +65,13 @@
 	if (S_ISREG(inode->i_mode) && file->f_mode & FMODE_WRITE &&
 	    (inode->i_size == 0)) {
 		struct jfs_inode_info *ji = JFS_IP(inode);
+		spin_lock_irq(&ji->ag_lock);
 		if (ji->active_ag == -1) {
 			ji->active_ag = ji->agno;
 			atomic_inc(
 			    &JFS_SBI(inode->i_sb)->bmap->db_active[ji->agno]);
 		}
+		spin_unlock_irq(&ji->ag_lock);
 	}
 
 	return 0;
@@ -78,11 +80,13 @@
 {
 	struct jfs_inode_info *ji = JFS_IP(inode);
 
+	spin_lock_irq(&ji->ag_lock);
 	if (ji->active_ag != -1) {
 		struct bmap *bmap = JFS_SBI(inode->i_sb)->bmap;
 		atomic_dec(&bmap->db_active[ji->active_ag]);
 		ji->active_ag = -1;
 	}
+	spin_unlock_irq(&ji->ag_lock);
 
 	return 0;
 }
diff -Nru a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
--- a/fs/jfs/jfs_dmap.c	2004-07-13 12:42:31 -07:00
+++ b/fs/jfs/jfs_dmap.c	2004-07-13 12:42:31 -07:00
@@ -1204,6 +1204,12 @@
 	s8 *leaf;
 	u32 mask;
 
+	if (dp->tree.leafidx != cpu_to_le32(LEAFIND)) {
+		jfs_error(bmp->db_ipbmap->i_sb,
+			  "dbAllocNext: Corrupt dmap page");
+		return -EIO;
+	}
+
 	/* pick up a pointer to the leaves of the dmap tree.
 	 */
 	leaf = dp->tree.stree + le32_to_cpu(dp->tree.leafidx);
@@ -1327,7 +1333,15 @@
 	    struct dmap * dp, s64 blkno, int nblocks, int l2nb, s64 * results)
 {
 	int word, lword, rc;
-	s8 *leaf = dp->tree.stree + le32_to_cpu(dp->tree.leafidx);
+	s8 *leaf;
+
+	if (dp->tree.leafidx != cpu_to_le32(LEAFIND)) {
+		jfs_error(bmp->db_ipbmap->i_sb,
+			  "dbAllocNear: Corrupt dmap page");
+		return -EIO;
+	}
+
+	leaf = dp->tree.stree + le32_to_cpu(dp->tree.leafidx);
 
 	/* determine the word within the dmap that holds the hint
 	 * (i.e. blkno).  also, determine the last word in the dmap
@@ -1489,6 +1503,13 @@
 	dcp = (struct dmapctl *) mp->data;
 	budmin = dcp->budmin;
 
+	if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) {
+		jfs_error(bmp->db_ipbmap->i_sb,
+			  "dbAllocAG: Corrupt dmapctl page");
+		release_metapage(mp);
+		return -EIO;
+	}
+
 	/* search the subtree(s) of the dmap control page that describes
 	 * the allocation group, looking for sufficient free space.  to begin,
 	 * determine how many allocation groups are represented in a dmap
@@ -1697,6 +1718,13 @@
 		dcp = (struct dmapctl *) mp->data;
 		budmin = dcp->budmin;
 
+		if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) {
+			jfs_error(bmp->db_ipbmap->i_sb,
+				  "dbFindCtl: Corrupt dmapctl page");
+			release_metapage(mp);
+			return -EIO;
+		}
+
 		/* search the tree within the dmap control page for
 		 * sufficent free space.  if sufficient free space is found,
 		 * dbFindLeaf() returns the index of the leaf at which
@@ -2458,6 +2486,13 @@
 	if (mp == NULL)
 		return -EIO;
 	dcp = (struct dmapctl *) mp->data;
+
+	if (dcp->leafidx != cpu_to_le32(CTLLEAFIND)) {
+		jfs_error(bmp->db_ipbmap->i_sb,
+			  "dbAdjCtl: Corrupt dmapctl page");
+		release_metapage(mp);
+		return -EIO;
+	}
 
 	/* determine the leaf number corresponding to the block and
 	 * the index within the dmap control tree.
diff -Nru a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c
--- a/fs/jfs/jfs_extent.c	2004-07-13 12:42:31 -07:00
+++ b/fs/jfs/jfs_extent.c	2004-07-13 12:42:31 -07:00
@@ -553,6 +553,7 @@
 
 	if (S_ISREG(ip->i_mode) && (ji->fileset == FILESYSTEM_I)) {
 		ag = BLKTOAG(daddr, sbi);
+		spin_lock_irq(&ji->ag_lock);
 		if (ji->active_ag == -1) {
 			atomic_inc(&bmp->db_active[ag]);
 			ji->active_ag = ag;
@@ -561,6 +562,7 @@
 			atomic_inc(&bmp->db_active[ag]);
 			ji->active_ag = ag;
 		}
+		spin_unlock_irq(&ji->ag_lock);
 	}
 
 	return (0);
diff -Nru a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
--- a/fs/jfs/jfs_imap.c	2004-07-13 12:42:31 -07:00
+++ b/fs/jfs/jfs_imap.c	2004-07-13 12:42:31 -07:00
@@ -1280,6 +1280,7 @@
 	 * to be freed by the transaction;  
 	 */
 	tid = txBegin(ipimap->i_sb, COMMIT_FORCE);
+	down(&JFS_IP(ipimap)->commit_sem);
 
 	/* acquire tlock of the iag page of the freed ixad 
 	 * to force the page NOHOMEOK (even though no data is
@@ -1312,6 +1313,7 @@
 	rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
 
 	txEnd(tid);
+	up(&JFS_IP(ipimap)->commit_sem);
 
 	/* unlock the AG inode map information */
 	AG_UNLOCK(imap, agno);
@@ -2622,10 +2624,13 @@
 		 */
 #endif				/*  _STILL_TO_PORT */
 		tid = txBegin(sb, COMMIT_FORCE);
+		down(&JFS_IP(ipimap)->commit_sem);
 
 		/* update the inode map addressing structure to point to it */
 		if ((rc =
 		     xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) {
+			txEnd(tid);
+			up(&JFS_IP(ipimap)->commit_sem);
 			/* Free the blocks allocated for the iag since it was
 			 * not successfully added to the inode map
 			 */
@@ -2650,6 +2655,7 @@
 		rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
 
 		txEnd(tid);
+		up(&JFS_IP(ipimap)->commit_sem);
 
 		duplicateIXtree(sb, blkno, xlen, &xaddr);
 
diff -Nru a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
--- a/fs/jfs/jfs_incore.h	2004-07-13 12:42:31 -07:00
+++ b/fs/jfs/jfs_incore.h	2004-07-13 12:42:31 -07:00
@@ -53,6 +53,7 @@
 	lid_t	blid;		/* lid of pseudo buffer?	*/
 	lid_t	atlhead;	/* anonymous tlock list head	*/
 	lid_t	atltail;	/* anonymous tlock list tail	*/
+	spinlock_t ag_lock;	/* protects active_ag		*/
 	struct list_head anon_inode_list; /* inodes having anonymous txns */
 	/*
 	 * rdwrlock serializes xtree between reads & writes and synchronizes
diff -Nru a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
--- a/fs/jfs/jfs_metapage.c	2004-07-13 12:42:31 -07:00
+++ b/fs/jfs/jfs_metapage.c	2004-07-13 12:42:31 -07:00
@@ -225,8 +225,16 @@
 
 	if (absolute)
 		mapping = inode->i_sb->s_bdev->bd_inode->i_mapping;
-	else
+	else {
+		/*
+		 * If an nfs client tries to read an inode that is larger
+		 * than any existing inodes, we may try to read past the
+		 * end of the inode map
+		 */
+		if ((lblock << inode->i_blkbits) >= inode->i_size)
+			return NULL;
 		mapping = inode->i_mapping;
+	}
 
 	hash_ptr = meta_hash(mapping, lblock);
 again:
diff -Nru a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
--- a/fs/jfs/jfs_xtree.c	2004-07-13 12:42:31 -07:00
+++ b/fs/jfs/jfs_xtree.c	2004-07-13 12:42:31 -07:00
@@ -1071,8 +1071,10 @@
 		 */
 		/* get/pin the parent page <sp> */
 		XT_GETPAGE(ip, parent->bn, smp, PSIZE, sp, rc);
-		if (rc)
-			goto errout2;
+		if (rc) {
+			XT_PUTPAGE(rcmp);
+			return rc;
+		}
 
 		/*
 		 * The new key entry goes ONE AFTER the index of parent entry,
@@ -1106,8 +1108,10 @@
 			rc = (sp->header.flag & BT_ROOT) ?
 			    xtSplitRoot(tid, ip, split, &rmp) :
 			    xtSplitPage(tid, ip, split, &rmp, &rbn);
-			if (rc)
-				goto errout1;
+			if (rc) {
+				XT_PUTPAGE(smp);
+				return rc;
+			}
 
 			XT_PUTPAGE(smp);
 			/* keep new child page <rp> pinned */
@@ -1170,19 +1174,6 @@
 	XT_PUTPAGE(rmp);
 
 	return 0;
-
-	/*
-	 * If something fails in the above loop we were already walking back
-	 * up the tree and the tree is now inconsistent.
-	 * release all pages we're holding.
-	 */
-      errout1:
-	XT_PUTPAGE(smp);
-
-      errout2:
-	XT_PUTPAGE(rcmp);
-
-	return rc;
 }
 
 
@@ -3504,7 +3495,17 @@
 	 * a page that was formerly to the right, let's make sure that the
 	 * next pointer is zero.
 	 */
-	p->header.next = 0;
+	if (p->header.next) {
+		if (log)
+			/*
+			 * Make sure this change to the header is logged.
+			 * If we really truncate this leaf, the flag
+			 * will be changed to tlckTRUNCATE
+			 */
+			tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW);
+		BT_MARK_DIRTY(mp, ip);
+		p->header.next = 0;
+	}
 
 	freed = 0;
 
diff -Nru a/fs/jfs/namei.c b/fs/jfs/namei.c
--- a/fs/jfs/namei.c	2004-07-13 12:42:31 -07:00
+++ b/fs/jfs/namei.c	2004-07-13 12:42:31 -07:00
@@ -1,5 +1,5 @@
 /*
- *   Copyright (C) International Business Machines Corp., 2000-2003
+ *   Copyright (C) International Business Machines Corp., 2000-2004
  *   Portions Copyright (C) Christoph Hellwig, 2001-2002
  *
  *   This program is free software;  you can redistribute it and/or modify
@@ -18,6 +18,7 @@
  */
 
 #include <linux/fs.h>
+#include <linux/ctype.h>
 #include "jfs_incore.h"
 #include "jfs_superblock.h"
 #include "jfs_inode.h"
@@ -43,6 +44,7 @@
  */
 struct inode_operations jfs_dir_inode_operations;
 struct file_operations jfs_dir_operations;
+struct dentry_operations jfs_ci_dentry_operations;
 
 static s64 commitZeroLink(tid_t, struct inode *);
 
@@ -1422,7 +1424,15 @@
 		return ERR_PTR(-EACCES);
 	}
 
-	return d_splice_alias(ip, dentry);
+	if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)
+		dentry->d_op = &jfs_ci_dentry_operations;
+
+	dentry = d_splice_alias(ip, dentry);
+
+	if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2))
+		dentry->d_op = &jfs_ci_dentry_operations;
+
+	return dentry;
 }
 
 struct dentry *jfs_get_parent(struct dentry *dentry)
@@ -1475,4 +1485,47 @@
 	.read		= generic_read_dir,
 	.readdir	= jfs_readdir,
 	.fsync		= jfs_fsync,
+};
+
+static int jfs_ci_hash(struct dentry *dir, struct qstr *this)
+{
+	unsigned long hash;
+	int i;
+
+	hash = init_name_hash();
+	for (i=0; i < this->len; i++)
+		hash = partial_name_hash(tolower(this->name[i]), hash);
+	this->hash = end_name_hash(hash);
+
+	return 0;
+}
+
+static int jfs_ci_compare(struct dentry *dir, struct qstr *a, struct qstr *b)
+{
+	int i, result = 1;
+
+	if (a->len != b->len)
+		goto out;
+	for (i=0; i < a->len; i++) {
+		if (tolower(a->name[i]) != tolower(b->name[i]))
+			goto out;
+	}
+	result = 0;
+
+	/*
+	 * We want creates to preserve case.  A negative dentry, a, that
+	 * has a different case than b may cause a new entry to be created
+	 * with the wrong case.  Since we can't tell if a comes from a negative
+	 * dentry, we blindly replace it with b.  This should be harmless if
+	 * a is not a negative dentry.
+	 */
+	memcpy((unsigned char *)a->name, b->name, a->len);
+out:
+	return result;
+}
+
+struct dentry_operations jfs_ci_dentry_operations =
+{
+	.d_hash = jfs_ci_hash,
+	.d_compare = jfs_ci_compare,
 };
diff -Nru a/fs/jfs/super.c b/fs/jfs/super.c
--- a/fs/jfs/super.c	2004-07-13 12:42:31 -07:00
+++ b/fs/jfs/super.c	2004-07-13 12:42:31 -07:00
@@ -82,6 +82,8 @@
 extern struct dentry *jfs_get_parent(struct dentry *dentry);
 extern int jfs_extendfs(struct super_block *, s64, int);
 
+extern struct dentry_operations jfs_ci_dentry_operations;
+
 #ifdef PROC_FS_JFS		/* see jfs_debug.h */
 extern void jfs_proc_init(void);
 extern void jfs_proc_clean(void);
@@ -141,10 +143,13 @@
 {
 	struct jfs_inode_info *ji = JFS_IP(inode);
 
+	spin_lock_irq(&ji->ag_lock);
 	if (ji->active_ag != -1) {
 		struct bmap *bmap = JFS_SBI(inode->i_sb)->bmap;
 		atomic_dec(&bmap->db_active[ji->active_ag]);
+		ji->active_ag = -1;
 	}
+	spin_unlock_irq(&ji->ag_lock);
 
 #ifdef CONFIG_JFS_POSIX_ACL
 	if (ji->i_acl != JFS_ACL_NOT_CACHED) {
@@ -443,6 +448,9 @@
 	if (!sb->s_root)
 		goto out_no_root;
 
+	if (sbi->mntflag & JFS_OS2)
+		sb->s_root->d_op = &jfs_ci_dentry_operations;
+
 	/* logical blocks are represented by 40 bits in pxd_t, etc. */
 	sb->s_maxbytes = ((u64) sb->s_blocksize) << 40;
 #if BITS_PER_LONG == 32
@@ -559,6 +567,7 @@
 		init_rwsem(&jfs_ip->rdwrlock);
 		init_MUTEX(&jfs_ip->commit_sem);
 		init_rwsem(&jfs_ip->xattr_sem);
+		spin_lock_init(&jfs_ip->ag_lock);
 		jfs_ip->active_ag = -1;
 #ifdef CONFIG_JFS_POSIX_ACL
 		jfs_ip->i_acl = JFS_ACL_NOT_CACHED;
