diff options
author | Dave Kleikamp <jfs.adm@hostme.bitkeeper.com> | 2004-07-13 22:50:57 -0700 |
---|---|---|
committer | Dave Kleikamp <jfs.adm@hostme.bitkeeper.com> | 2004-07-13 22:50:57 -0700 |
commit | dbd1a7bfced6ae7f13c1ef7bc2a5e2d73358d4d1 (patch) | |
tree | b106a747709a2df27c9444c418345061560aff65 /fs | |
parent | 1ade820cf5dea55593200f611534027902ee65a2 (diff) | |
parent | 6e50a7fe01bb676b2bddc1c5a01ea1a1dbfc3fbf (diff) | |
download | history-dbd1a7bfced6ae7f13c1ef7bc2a5e2d73358d4d1.tar.gz |
Merge bk://linux.bkbits.net/linux-2.5
into hostme.bitkeeper.com:/repos/j/jfs/linux-2.5
Diffstat (limited to 'fs')
-rw-r--r-- | fs/jfs/file.c | 4 | ||||
-rw-r--r-- | fs/jfs/jfs_dmap.c | 37 | ||||
-rw-r--r-- | fs/jfs/jfs_extent.c | 2 | ||||
-rw-r--r-- | fs/jfs/jfs_imap.c | 6 | ||||
-rw-r--r-- | fs/jfs/jfs_incore.h | 1 | ||||
-rw-r--r-- | fs/jfs/jfs_metapage.c | 10 | ||||
-rw-r--r-- | fs/jfs/jfs_xtree.c | 37 | ||||
-rw-r--r-- | fs/jfs/namei.c | 57 | ||||
-rw-r--r-- | fs/jfs/super.c | 9 |
9 files changed, 141 insertions, 22 deletions
diff --git a/fs/jfs/file.c b/fs/jfs/file.c index 67e4ba8ce0956c..a87b06fa8ff899 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -65,11 +65,13 @@ static int jfs_open(struct inode *inode, struct file *file) 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 @@ static int jfs_release(struct inode *inode, struct file *file) { 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 --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 1b55df36f5cc7a..ed734330504e10 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -1204,6 +1204,12 @@ static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno, 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 @@ dbAllocNear(struct bmap * bmp, 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 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) 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 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno) 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 @@ -2459,6 +2487,13 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) 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 --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c index 2068c4746e029d..2b411bc32eb833 100644 --- a/fs/jfs/jfs_extent.c +++ b/fs/jfs/jfs_extent.c @@ -553,6 +553,7 @@ extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno) 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 @@ extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno) atomic_inc(&bmp->db_active[ag]); ji->active_ag = ag; } + spin_unlock_irq(&ji->ag_lock); } return (0); diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index 86246f4db7a6fd..cfb582d2821743 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -1280,6 +1280,7 @@ int diFree(struct inode *ip) * 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 @@ int diFree(struct inode *ip) 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 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) */ #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 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE); txEnd(tid); + up(&JFS_IP(ipimap)->commit_sem); duplicateIXtree(sb, blkno, xlen, &xaddr); diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h index ac608c9ff5307a..5496bfb149cf20 100644 --- a/fs/jfs/jfs_incore.h +++ b/fs/jfs/jfs_incore.h @@ -53,6 +53,7 @@ struct jfs_inode_info { 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 --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index dd6578b7d3b260..831ee09c2b9b79 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -225,8 +225,16 @@ struct metapage *__get_metapage(struct inode *inode, unsigned long lblock, 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 --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c index 5aa647326887e3..19913fcd4c332a 100644 --- a/fs/jfs/jfs_xtree.c +++ b/fs/jfs/jfs_xtree.c @@ -1071,8 +1071,10 @@ xtSplitUp(tid_t tid, */ /* 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 @@ xtSplitUp(tid_t tid, 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 @@ xtSplitUp(tid_t tid, 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 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag) * 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 --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 871371d5a1aa32..8c3a8e78d0f8ce 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -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 @@ extern int jfs_init_acl(struct inode *, struct inode *); */ 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 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc 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) @@ -1476,3 +1486,46 @@ struct file_operations jfs_dir_operations = { .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 --git a/fs/jfs/super.c b/fs/jfs/super.c index 18fdb77086a0ee..9615a83d7ef016 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -82,6 +82,8 @@ extern void jfs_write_inode(struct inode *inode, int wait); 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 @@ static void jfs_destroy_inode(struct inode *inode) { 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 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) 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 @@ static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) 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; |