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 # Signed-off-by: Dave Kleikamp # # 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 # # 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 # # 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 # # 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 # # 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 # # 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 # # 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 */ 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 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 +#include #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;