From 9aa9eb41942b918f385ccabd2efdd6e7e4232165 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 8 Aug 2000 12:37:17 +0000 Subject: Merge with Linux 2.4.0-test6-pre1. --- fs/binfmt_elf.c | 2 +- fs/binfmt_misc.c | 8 +- fs/binfmt_script.c | 6 +- fs/buffer.c | 16 ++- fs/dcache.c | 1 + fs/devices.c | 8 +- fs/exec.c | 12 +- fs/ext2/balloc.c | 57 +++++---- fs/ext2/file.c | 6 +- fs/ext2/inode.c | 342 +++++++++++++++++++++++++++++++++-------------------- fs/ext2/super.c | 89 +++++++------- fs/fat/dir.c | 2 +- fs/vfat/namei.c | 2 +- 13 files changed, 330 insertions(+), 221 deletions(-) (limited to 'fs') diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 4fb5b1685..422531158 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -512,7 +512,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) retval = PTR_ERR(interpreter); if (IS_ERR(interpreter)) goto out_free_interp; - retval = kernel_read(interpreter, 0, bprm->buf, 128); + retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE); if (retval < 0) goto out_free_dentry; diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index f9c30df1b..c16536479 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -182,7 +182,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) { struct binfmt_entry *fmt; struct file * file; - char iname[128]; + char iname[BINPRM_BUF_SIZE]; char *iname_addr = iname; int retval; @@ -194,8 +194,8 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) read_lock(&entries_lock); fmt = check_file(bprm); if (fmt) { - strncpy(iname, fmt->interpreter, 127); - iname[127] = '\0'; + strncpy(iname, fmt->interpreter, BINPRM_BUF_SIZE - 1); + iname[BINPRM_BUF_SIZE - 1] = '\0'; } read_unlock(&entries_lock); if (!fmt) @@ -324,7 +324,7 @@ static int proc_write_register(struct file *file, const char *buffer, /* more sanity checks */ if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) || - (e->size < 1) || ((e->size + e->offset) > 127) || + (e->size < 1) || ((e->size + e->offset) > (BINPRM_BUF_SIZE - 1)) || !(e->proc_name) || !(e->interpreter) || entry_proc_setup(e)) goto free_err; diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c index 3d5023e2d..ae7de4c24 100644 --- a/fs/binfmt_script.c +++ b/fs/binfmt_script.c @@ -18,7 +18,7 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs) { char *cp, *i_name, *i_arg; struct file *file; - char interp[128]; + char interp[BINPRM_BUF_SIZE]; int retval; if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang)) @@ -33,9 +33,9 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs) fput(bprm->file); bprm->file = NULL; - bprm->buf[127] = '\0'; + bprm->buf[BINPRM_BUF_SIZE - 1] = '\0'; if ((cp = strchr(bprm->buf, '\n')) == NULL) - cp = bprm->buf+127; + cp = bprm->buf+BINPRM_BUF_SIZE-1; *cp = '\0'; while (cp > bprm->buf) { cp--; diff --git a/fs/buffer.c b/fs/buffer.c index dad4fbcfb..341dfe591 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1341,13 +1341,27 @@ static void create_empty_buffers(struct page *page, struct inode *inode, unsigne page_cache_get(page); } +/* + * We are taking a block for data and we don't want any output from any + * buffer-cache aliases starting from return from that function and + * until the moment when something will explicitly mark the buffer + * dirty (hopefully that will not happen until we will free that block ;-) + * We don't even need to mark it not-uptodate - nobody can expect + * anything from a newly allocated buffer anyway. We used to used + * unmap_buffer() for such invalidation, but that was wrong. We definitely + * don't want to mark the alias unmapped, for example - it would confuse + * anyone who might pick it with bread() afterwards... + */ + static void unmap_underlying_metadata(struct buffer_head * bh) { struct buffer_head *old_bh; old_bh = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size); if (old_bh) { - unmap_buffer(old_bh); + mark_buffer_clean(old_bh); + wait_on_buffer(old_bh); + clear_bit(BH_Req, &old_bh->b_state); /* Here we could run brelse or bforget. We use bforget because it will try to put the buffer in the freelist. */ diff --git a/fs/dcache.c b/fs/dcache.c index 729b48855..9be3e8cdc 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -14,6 +14,7 @@ * the dcache entry is deleted or garbage collected. */ +#include #include #include #include diff --git a/fs/devices.c b/fs/devices.c index dd7db7730..85fb7e519 100644 --- a/fs/devices.c +++ b/fs/devices.c @@ -88,11 +88,11 @@ static struct file_operations * get_chrfops(unsigned int major, unsigned int min char name[20]; sprintf(name, "char-major-%d", major); request_module(name); - } - read_lock(&chrdevs_lock); - ret = fops_get(chrdevs[major].fops); - read_unlock(&chrdevs_lock); + read_lock(&chrdevs_lock); + ret = fops_get(chrdevs[major].fops); + read_unlock(&chrdevs_lock); + } #endif return ret; } diff --git a/fs/exec.c b/fs/exec.c index d28aaec82..f7745f9de 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -555,7 +555,7 @@ static inline int must_not_trace_exec(struct task_struct * p) /* * Fill the binprm structure from the inode. - * Check permissions, then read the first 512 bytes + * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes */ int prepare_binprm(struct linux_binprm *bprm) { @@ -646,8 +646,8 @@ int prepare_binprm(struct linux_binprm *bprm) } } - memset(bprm->buf,0,sizeof(bprm->buf)); - return kernel_read(bprm->file,0,bprm->buf,128); + memset(bprm->buf,0,BINPRM_BUF_SIZE); + return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE); } /* @@ -819,15 +819,15 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs int retval; int i; - bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); - memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); - file = open_exec(filename); retval = PTR_ERR(file); if (IS_ERR(file)) return retval; + bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); + memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); + bprm.file = file; bprm.filename = filename; bprm.sh_bang = 0; diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index a3f8ae4ce..8ca28e0a0 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -16,7 +16,6 @@ #include #include - /* * balloc.c contains the blocks allocation and deallocation routines */ @@ -379,10 +378,8 @@ int ext2_new_block (const struct inode * inode, unsigned long goal, ((sb->u.ext2_sb.s_resuid != current->fsuid) && (sb->u.ext2_sb.s_resgid == 0 || !in_group_p (sb->u.ext2_sb.s_resgid)) && - !capable(CAP_SYS_RESOURCE))) { - unlock_super (sb); - return 0; - } + !capable(CAP_SYS_RESOURCE))) + goto out; ext2_debug ("goal=%lu.\n", goal); @@ -475,16 +472,13 @@ repeat: gdp = ext2_get_group_desc (sb, i, &bh2); if (!gdp) { *err = -EIO; - unlock_super (sb); - return 0; + goto out; } if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) break; } - if (k >= sb->u.ext2_sb.s_groups_count) { - unlock_super (sb); - return 0; - } + if (k >= sb->u.ext2_sb.s_groups_count) + goto out; bitmap_nr = load_block_bitmap (sb, i); if (bitmap_nr < 0) goto io_error; @@ -500,8 +494,7 @@ repeat: if (j >= EXT2_BLOCKS_PER_GROUP(sb)) { ext2_error (sb, "ext2_new_block", "Free blocks count corrupted for block group %d", i); - unlock_super (sb); - return 0; + goto out; } search_back: @@ -520,9 +513,8 @@ got_block: * Check quota for allocation of this block. */ if(DQUOT_ALLOC_BLOCK(sb, inode, 1)) { - unlock_super(sb); *err = -EDQUOT; - return 0; + goto out; } tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + le32_to_cpu(es->s_first_data_block); @@ -550,31 +542,50 @@ got_block: #ifdef EXT2_PREALLOCATE if (prealloc_block) { int prealloc_goal; + unsigned long next_block = tmp + 1; prealloc_goal = es->s_prealloc_blocks ? es->s_prealloc_blocks : EXT2_DEFAULT_PREALLOC_BLOCKS; + /* Writer: ->i_prealloc* */ + /* + * Can't happen right now, will need handling if we go for + * per-group spinlocks. Handling == skipping preallocation if + * condition below will be true. For now there is no legitimate + * way it could happen, thus the BUG(). + */ + if (*prealloc_count) + BUG(); *prealloc_count = 0; - *prealloc_block = tmp + 1; + *prealloc_block = next_block; + /* Writer: end */ for (k = 1; k < prealloc_goal && (j + k) < EXT2_BLOCKS_PER_GROUP(sb); - k++) { + k++, next_block++) { if (DQUOT_PREALLOC_BLOCK(sb, inode, 1)) break; - if (ext2_set_bit (j + k, bh->b_data)) { + /* Writer: ->i_prealloc* */ + if (*prealloc_block + *prealloc_count != next_block || + ext2_set_bit (j + k, bh->b_data)) { + /* Writer: end */ DQUOT_FREE_BLOCK(sb, inode, 1); break; } (*prealloc_count)++; + /* Writer: end */ } + /* + * As soon as we go for per-group spinlocks we'll need these + * done inside the loop above. + */ gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - - *prealloc_count); + (k - 1)); es->s_free_blocks_count = cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - - *prealloc_count); + (k - 1)); ext2_debug ("Preallocated a further %lu bits.\n", - *prealloc_count); + (k - 1)); } #endif @@ -591,8 +602,7 @@ got_block: "block(%d) >= blocks count(%d) - " "block_group = %d, es == %p ",j, le32_to_cpu(es->s_blocks_count), i, es); - unlock_super (sb); - return 0; + goto out; } ext2_debug ("allocating block %d. " @@ -609,6 +619,7 @@ got_block: io_error: *err = -EIO; +out: unlock_super (sb); return 0; diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 1b9983e24..27b1fcbcb 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -20,7 +20,6 @@ #include #include -#include static loff_t ext2_file_lseek(struct file *, loff_t, int); static int ext2_open_file (struct inode *, struct file *); @@ -74,11 +73,8 @@ static loff_t ext2_file_lseek( */ static int ext2_release_file (struct inode * inode, struct file * filp) { - if (filp->f_mode & FMODE_WRITE) { - lock_kernel(); + if (filp->f_mode & FMODE_WRITE) ext2_discard_prealloc (inode); - unlock_kernel(); - } return 0; } diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 4580c87e0..c7234e7b5 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -35,9 +35,7 @@ static int ext2_update_inode(struct inode * inode, int do_sync); */ void ext2_put_inode (struct inode * inode) { - lock_kernel(); ext2_discard_prealloc (inode); - unlock_kernel(); } /* @@ -66,19 +64,6 @@ no_delete: clear_inode(inode); /* We must guarantee clearing of inode... */ } -#define inode_bmap(inode, nr) (le32_to_cpu((inode)->u.ext2_i.i_data[(nr)])) - -static inline int block_bmap (struct buffer_head * bh, int nr) -{ - int tmp; - - if (!bh) - return 0; - tmp = le32_to_cpu(((u32 *) bh->b_data)[nr]); - brelse (bh); - return tmp; -} - /* * ext2_discard_prealloc and ext2_alloc_block are atomic wrt. the * superblock in the same manner as are ext2_free_blocks and @@ -91,11 +76,13 @@ void ext2_discard_prealloc (struct inode * inode) #ifdef EXT2_PREALLOCATE unsigned short total; + lock_kernel(); if (inode->u.ext2_i.i_prealloc_count) { total = inode->u.ext2_i.i_prealloc_count; inode->u.ext2_i.i_prealloc_count = 0; ext2_free_blocks (inode, inode->u.ext2_i.i_prealloc_block, total); } + unlock_kernel(); #endif } @@ -135,69 +122,181 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err) return result; } -static inline long ext2_block_map (struct inode * inode, long block) +typedef struct { + u32 *p; + u32 key; + struct buffer_head *bh; +} Indirect; + +static inline void add_chain(Indirect *p, struct buffer_head *bh, u32 *v) +{ + p->key = *(p->p = v); + p->bh = bh; +} + +static inline int verify_chain(Indirect *from, Indirect *to) +{ + while (from <= to && from->key == *from->p) + from++; + return (from > to); +} + +/** + * ext2_block_to_path - parse the block number into array of offsets + * @inode: inode in question (we are only interested in its superblock) + * @i_block: block number to be parsed + * @offsets: array to store the offsets in + * + * To store the locations of file's data ext2 uses a data structure common + * for UNIX filesystems - tree of pointers anchored in the inode, with + * data blocks at leaves and indirect blocks in intermediate nodes. + * This function translates the block number into path in that tree - + * return value is the path length and @offsets[n] is the offset of + * pointer to (n+1)th node in the nth one. If @block is out of range + * (negative or too large) warning is printed and zero returned. + * + * Note: function doesn't find node addresses, so no IO is needed. All + * we need to know is the capacity of indirect blocks (taken from the + * inode->i_sb). + */ + +/* + * Portability note: the last comparison (check that we fit into triple + * indirect block) is spelled differently, because otherwise on an + * architecture with 32-bit longs and 8Kb pages we might get into trouble + * if our filesystem had 8Kb blocks. We might use long long, but that would + * kill us on x86. Oh, well, at least the sign propagation does not matter - + * i_block would have to be negative in the very beginning, so we would not + * get there at all. + */ + +static int ext2_block_to_path(struct inode *inode, long i_block, int offsets[4]) { - int i, ret; int ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb); int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb); - - ret = 0; - lock_kernel(); - if (block < 0) { - ext2_warning (inode->i_sb, "ext2_block_map", "block < 0"); - goto out; - } - if (block >= EXT2_NDIR_BLOCKS + ptrs + - (1 << (ptrs_bits * 2)) + - ((1 << (ptrs_bits * 2)) << ptrs_bits)) { - ext2_warning (inode->i_sb, "ext2_block_map", "block > big"); - goto out; - } - if (block < EXT2_NDIR_BLOCKS) { - ret = inode_bmap (inode, block); - goto out; - } - block -= EXT2_NDIR_BLOCKS; - if (block < ptrs) { - i = inode_bmap (inode, EXT2_IND_BLOCK); - if (!i) - goto out; - ret = block_bmap (bread (inode->i_dev, i, - inode->i_sb->s_blocksize), block); - goto out; + const long direct_blocks = EXT2_NDIR_BLOCKS, + indirect_blocks = ptrs, + double_blocks = (1 << (ptrs_bits * 2)); + int n = 0; + + if (i_block < 0) { + ext2_warning (inode->i_sb, "ext2_block_to_path", "block < 0"); + } else if (i_block < direct_blocks) { + offsets[n++] = i_block; + } else if ( (i_block -= direct_blocks) < indirect_blocks) { + offsets[n++] = EXT2_IND_BLOCK; + offsets[n++] = i_block; + } else if ((i_block -= indirect_blocks) < double_blocks) { + offsets[n++] = EXT2_DIND_BLOCK; + offsets[n++] = i_block >> ptrs_bits; + offsets[n++] = i_block & (ptrs - 1); + } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { + offsets[n++] = EXT2_TIND_BLOCK; + offsets[n++] = i_block >> (ptrs_bits * 2); + offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); + offsets[n++] = i_block & (ptrs - 1); + } else { + ext2_warning (inode->i_sb, "ext2_block_to_path", "block > big"); } - block -= ptrs; - if (block < (1 << (ptrs_bits * 2))) { - i = inode_bmap (inode, EXT2_DIND_BLOCK); - if (!i) - goto out; - i = block_bmap (bread (inode->i_dev, i, - inode->i_sb->s_blocksize), - block >> ptrs_bits); - if (!i) - goto out; - ret = block_bmap (bread (inode->i_dev, i, - inode->i_sb->s_blocksize), - block & (ptrs - 1)); - goto out; + return n; +} + +/** + * ext2_get_branch - read the chain of indirect blocks leading to data + * @inode: inode in question + * @depth: depth of the chain (1 - direct pointer, etc.) + * @offsets: offsets of pointers in inode/indirect blocks + * @chain: place to store the result + * @err: here we store the error value + * + * Function fills the array of triples and returns %NULL + * if everything went OK or the pointer to the last filled triple + * (incomplete one) otherwise. Upon the return chain[i].key contains + * the number of (i+1)-th block in the chain (as it is stored in memory, + * i.e. little-endian 32-bit), chain[i].p contains the address of that + * number (it points into struct inode for i==0 and into the bh->b_data + * for i>0) and chain[i].bh points to the buffer_head of i-th indirect + * block for i>0 and NULL for i==0. In other words, it holds the block + * numbers of the chain, addresses they were taken from (and where we can + * verify that chain did not change) and buffer_heads hosting these + * numbers. + * + * Function stops when it stumbles upon zero pointer (absent block) + * (pointer to last triple returned, *@err == 0) + * or when it gets an IO error reading an indirect block + * (ditto, *@err == -EIO) + * or when it notices that chain had been changed while it was reading + * (ditto, *@err == -EAGAIN) + * or when it reads all @depth-1 indirect blocks successfully and finds + * the whole chain, all way to the data (returns %NULL, *err == 0). + */ +static inline Indirect *ext2_get_branch(struct inode *inode, + int depth, + int *offsets, + Indirect chain[4], + int *err) +{ + kdev_t dev = inode->i_dev; + int size = inode->i_sb->s_blocksize; + Indirect *p = chain; + struct buffer_head *bh; + + *err = 0; + /* i_data is not going away, no lock needed */ + add_chain (chain, NULL, inode->u.ext2_i.i_data + *offsets); + if (!p->key) + goto no_block; + /* + * switch below is merely an unrolled loop - body should be + * repeated depth-1 times. Maybe loop would be actually better, + * but that way we get straight execution path in normal cases. + * Easy to change, anyway - all cases in switch are literally + * identical. + */ + switch (depth) { + case 4: + bh = bread(dev, le32_to_cpu(p->key), size); + if (!bh) + goto failure; + /* Reader: pointers */ + if (!verify_chain(chain, p)) + goto changed; + add_chain(++p, bh, (u32*)bh->b_data + *++offsets); + /* Reader: end */ + if (!p->key) + goto no_block; + case 3: + bh = bread(dev, le32_to_cpu(p->key), size); + if (!bh) + goto failure; + /* Reader: pointers */ + if (!verify_chain(chain, p)) + goto changed; + add_chain(++p, bh, (u32*)bh->b_data + *++offsets); + /* Reader: end */ + if (!p->key) + goto no_block; + case 2: + bh = bread(dev, le32_to_cpu(p->key), size); + if (!bh) + goto failure; + /* Reader: pointers */ + if (!verify_chain(chain, p)) + goto changed; + add_chain(++p, bh, (u32*)bh->b_data + *++offsets); + /* Reader: end */ + if (!p->key) + goto no_block; } - block -= (1 << (ptrs_bits * 2)); - i = inode_bmap (inode, EXT2_TIND_BLOCK); - if (!i) - goto out; - i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), - block >> (ptrs_bits * 2)); - if (!i) - goto out; - i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), - (block >> ptrs_bits) & (ptrs - 1)); - if (!i) - goto out; - ret = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), - block & (ptrs - 1)); -out: - unlock_kernel(); - return ret; + return NULL; + +changed: + *err = -EAGAIN; + goto no_block; +failure: + *err = -EIO; +no_block: + return p; } static struct buffer_head * inode_getblk (struct inode * inode, int nr, @@ -396,28 +495,37 @@ static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head * { int ret, err, new; struct buffer_head *bh; - unsigned long ptr, phys; - /* - * block pointers per block - */ - unsigned long ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb); - int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb); - const int direct_blocks = EXT2_NDIR_BLOCKS, - indirect_blocks = ptrs, - double_blocks = (1 << (ptrs_bits * 2)), - triple_blocks = (1 << (ptrs_bits * 3)); + unsigned long phys; + int offsets[4]; + int *p; + Indirect chain[4]; + Indirect *partial; + int depth; + + depth = ext2_block_to_path(inode, iblock, offsets); + if (depth == 0) + goto abort; + + lock_kernel(); + partial = ext2_get_branch(inode, depth, offsets, chain, &err); + + if (!partial) { + unlock_kernel(); + for (partial = chain + depth - 1; partial > chain; partial--) + brelse(partial->bh); + bh_result->b_dev = inode->i_dev; + bh_result->b_blocknr = le32_to_cpu(chain[depth-1].key); + bh_result->b_state |= (1UL << BH_Mapped); + return 0; + } + + while (partial > chain) { + brelse(partial->bh); + partial--; + } if (!create) { - /* - * Will clean this up further, ext2_block_map() should use the - * bh instead of an integer block-number interface. - */ - phys = ext2_block_map(inode, iblock); - if (phys) { - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); - } + unlock_kernel(); return 0; } @@ -426,14 +534,6 @@ static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head * ret = 0; bh = NULL; - lock_kernel(); - - if (iblock < 0) - goto abort_negative; - if (iblock > direct_blocks + indirect_blocks + - double_blocks + triple_blocks) - goto abort_too_big; - /* * If this is a sequential block allocation, set the next_alloc_block * to this block now so that all the indblock and data block @@ -450,7 +550,6 @@ static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head * } err = 0; - ptr = iblock; /* * ok, these macros clean the logic up a bit and make @@ -465,27 +564,20 @@ static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head * #define GET_INDIRECT_PTR(x) \ block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL); - if (ptr < direct_blocks) { - bh = GET_INODE_DATABLOCK(ptr); + p = offsets; + if (depth == 1) { + bh = GET_INODE_DATABLOCK(*p); goto out; } - ptr -= direct_blocks; - if (ptr < indirect_blocks) { - bh = GET_INODE_PTR(EXT2_IND_BLOCK); - goto get_indirect; + bh = GET_INODE_PTR(*p); + switch (depth) { + default: /* case 4: */ + bh = GET_INDIRECT_PTR(*++p); + case 3: + bh = GET_INDIRECT_PTR(*++p); + case 2: + bh = GET_INDIRECT_DATABLOCK(*++p); } - ptr -= indirect_blocks; - if (ptr < double_blocks) { - bh = GET_INODE_PTR(EXT2_DIND_BLOCK); - goto get_double; - } - ptr -= double_blocks; - bh = GET_INODE_PTR(EXT2_TIND_BLOCK); - bh = GET_INDIRECT_PTR(ptr >> (ptrs_bits * 2)); -get_double: - bh = GET_INDIRECT_PTR((ptr >> ptrs_bits) & (ptrs - 1)); -get_indirect: - bh = GET_INDIRECT_DATABLOCK(ptr & (ptrs - 1)); #undef GET_INODE_DATABLOCK #undef GET_INODE_PTR @@ -505,17 +597,9 @@ out: bh_result->b_state |= (1UL << BH_Mapped); /* safe */ if (new) bh_result->b_state |= (1UL << BH_New); -abort: unlock_kernel(); +abort: return err; - -abort_negative: - ext2_warning (inode->i_sb, "ext2_get_block", "block < 0"); - goto abort; - -abort_too_big: - ext2_warning (inode->i_sb, "ext2_get_block", "block > big"); - goto abort; } struct buffer_head * ext2_getblk(struct inode * inode, long block, int create, int * err) diff --git a/fs/ext2/super.c b/fs/ext2/super.c index e395c75a1..bca514ee5 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -254,53 +254,56 @@ static int parse_options (char * options, unsigned long * sb_block, return 1; } -static void ext2_setup_super (struct super_block * sb, - struct ext2_super_block * es) +static int ext2_setup_super (struct super_block * sb, + struct ext2_super_block * es, + int read_only) { + int res = 0; if (le32_to_cpu(es->s_rev_level) > EXT2_MAX_SUPP_REV) { printk ("EXT2-fs warning: revision level too high, " "forcing read/only mode\n"); - sb->s_flags |= MS_RDONLY; + res = MS_RDONLY; } - if (!(sb->s_flags & MS_RDONLY)) { - if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) - printk ("EXT2-fs warning: mounting unchecked fs, " - "running e2fsck is recommended\n"); - else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS)) - printk ("EXT2-fs warning: mounting fs with errors, " - "running e2fsck is recommended\n"); - else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && - le16_to_cpu(es->s_mnt_count) >= - (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) - printk ("EXT2-fs warning: maximal mount count reached, " - "running e2fsck is recommended\n"); - else if (le32_to_cpu(es->s_checkinterval) && - (le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME)) - printk ("EXT2-fs warning: checktime reached, " - "running e2fsck is recommended\n"); - es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS); - if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) - es->s_max_mnt_count = (__s16) cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT); - es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1); - es->s_mtime = cpu_to_le32(CURRENT_TIME); - mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); - sb->s_dirt = 1; - if (test_opt (sb, DEBUG)) - printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, " - "bpg=%lu, ipg=%lu, mo=%04lx]\n", - EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize, - sb->u.ext2_sb.s_frag_size, - sb->u.ext2_sb.s_groups_count, - EXT2_BLOCKS_PER_GROUP(sb), - EXT2_INODES_PER_GROUP(sb), - sb->u.ext2_sb.s_mount_opt); + if (read_only) + return res; + if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) + printk ("EXT2-fs warning: mounting unchecked fs, " + "running e2fsck is recommended\n"); + else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS)) + printk ("EXT2-fs warning: mounting fs with errors, " + "running e2fsck is recommended\n"); + else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && + le16_to_cpu(es->s_mnt_count) >= + (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) + printk ("EXT2-fs warning: maximal mount count reached, " + "running e2fsck is recommended\n"); + else if (le32_to_cpu(es->s_checkinterval) && + (le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME)) + printk ("EXT2-fs warning: checktime reached, " + "running e2fsck is recommended\n"); + es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS); + if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) + es->s_max_mnt_count = (__s16) cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT); + es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1); + es->s_mtime = cpu_to_le32(CURRENT_TIME); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + sb->s_dirt = 1; + if (test_opt (sb, DEBUG)) + printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, " + "bpg=%lu, ipg=%lu, mo=%04lx]\n", + EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize, + sb->u.ext2_sb.s_frag_size, + sb->u.ext2_sb.s_groups_count, + EXT2_BLOCKS_PER_GROUP(sb), + EXT2_INODES_PER_GROUP(sb), + sb->u.ext2_sb.s_mount_opt); #ifdef CONFIG_EXT2_CHECK - if (test_opt (sb, CHECK)) { - ext2_check_blocks_bitmap (sb); - ext2_check_inodes_bitmap (sb); - } -#endif + if (test_opt (sb, CHECK)) { + ext2_check_blocks_bitmap (sb); + ext2_check_inodes_bitmap (sb); } +#endif + return res; } static int ext2_check_descriptors (struct super_block * sb) @@ -601,7 +604,7 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, printk ("EXT2-fs: get root inode failed\n"); return NULL; } - ext2_setup_super (sb, es); + ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY); return sb; } @@ -685,8 +688,8 @@ int ext2_remount (struct super_block * sb, int * flags, char * data) * by e2fsck since we originally mounted the partition.) */ sb->u.ext2_sb.s_mount_state = le16_to_cpu(es->s_state); - sb->s_flags &= ~MS_RDONLY; - ext2_setup_super (sb, es); + if (!ext2_setup_super (sb, es, 0)) + sb->s_flags &= ~MS_RDONLY; } return 0; } diff --git a/fs/fat/dir.c b/fs/fat/dir.c index c7ea5cfe5..bbb895285 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -10,7 +10,7 @@ * VFAT extensions by Gordon Chaffee * Merged with msdos fs by Henrik Storner * Rewritten for constant inumbers. Plugged buffer overrun in readdir(). AV - * Short name translation 1999 by Wolfram Pienkoss + * Short name translation 1999 by Wolfram Pienkoss */ #define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index 3895b0774..b3fcf2088 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -9,7 +9,7 @@ * what file operation caused you trouble and if you can duplicate * the problem, send a script that demonstrates it. * - * Short name translation 1999 by Wolfram Pienkoss + * Short name translation 1999 by Wolfram Pienkoss */ #define __NO_VERSION__ -- cgit v1.2.3