diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2001-04-05 04:55:58 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2001-04-05 04:55:58 +0000 |
commit | 74a9f2e1b4d3ab45a9f72cb5b556c9f521524ab3 (patch) | |
tree | 7c4cdb103ab1b388c9852a88bd6fb1e73eba0b5c /fs | |
parent | ee6374c8b0d333c08061c6a97bc77090d7461225 (diff) |
Merge with Linux 2.4.3.
Note that mingetty does no longer work with serial console, you have to
switch to another getty like getty_ps. This commit also includes a
fix for a setitimer bug which did prevent getty_ps from working on
older kernels.
Diffstat (limited to 'fs')
53 files changed, 333 insertions, 319 deletions
diff --git a/fs/Makefile b/fs/Makefile index 738e4418c..998909436 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -7,7 +7,7 @@ O_TARGET := fs.o -export-objs := filesystems.o +export-objs := filesystems.o dcache.o mod-subdirs := nls obj-y := open.o read_write.o devices.o file_table.o buffer.o \ diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 83ba97166..ff11b6e9b 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -385,6 +385,12 @@ struct super_block *adfs_read_super(struct super_block *sb, void *data, int sile sb->u.adfs_sb.s_size = adfs_discsize(dr, sb->s_blocksize_bits); sb->u.adfs_sb.s_version = dr->format_version; sb->u.adfs_sb.s_log2sharesize = dr->log2sharesize; + + /* + * Max file size is 2Gb + */ + + sb->s_maxbytes = MAX_NON_LFS; sb->u.adfs_sb.s_map = adfs_read_map(sb, dr); if (!sb->u.adfs_sb.s_map) diff --git a/fs/affs/super.c b/fs/affs/super.c index c77c3410c..78aa98372 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -415,6 +415,12 @@ got_root: s->s_flags |= MS_NODEV | MS_NOSUID; + /* + * Max file size is 2Gb + */ + + s->s_maxbytes = MAX_NON_LFS; + /* Keep super block in cache */ bb = affs_bread(dev,root_block,s->s_blocksize); if (!bb) diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 8e33b4ab2..ce6e778eb 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -250,6 +250,7 @@ static struct super_block * bfs_read_super(struct super_block * s, set_blocksize(dev, BFS_BSIZE); s->s_blocksize = BFS_BSIZE; s->s_blocksize_bits = BFS_BSIZE_BITS; + s->s_maxbytes = MAX_NON_LFS; bh = bread(dev, 0, BFS_BSIZE); if(!bh) diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 42f746fb7..8a907e037 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -342,7 +342,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) error = bprm->file->f_op->read(bprm->file, (char *)text_addr, ex.a_text+ex.a_data, &pos); - if (error < 0) { + if ((signed long)error < 0) { send_sig(SIGKILL, current, 0); return error; } @@ -377,24 +377,24 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) goto beyond_if; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_TXTADDR(ex), ex.a_text, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (error != N_TXTADDR(ex)) { send_sig(SIGKILL, current, 0); return error; } - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (error != N_DATADDR(ex)) { send_sig(SIGKILL, current, 0); return error; @@ -476,12 +476,12 @@ static int load_aout_library(struct file *file) goto out; } /* Now use mmap to map the library into memory. */ - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(file, start_addr, ex.a_text + ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, N_TXTOFF(ex)); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); retval = error; if (error != start_addr) goto out; diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 6841b4acb..7538f9b2c 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -214,11 +214,11 @@ elf_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int pro { unsigned long map_addr; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); map_addr = do_mmap(filep, ELF_PAGESTART(addr), eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type, eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr)); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return(map_addr); } @@ -732,10 +732,10 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) Since we do not have the power to recompile these, we emulate the SVr4 behavior. Sigh. */ /* N.B. Shouldn't the size here be PAGE_SIZE?? */ - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); } #ifdef ELF_PLAT_INIT @@ -816,7 +816,7 @@ static int load_elf_library(struct file *file) while (elf_phdata->p_type != PT_LOAD) elf_phdata++; /* Now use mmap to map the library into memory. */ - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); error = do_mmap(file, ELF_PAGESTART(elf_phdata->p_vaddr), (elf_phdata->p_filesz + @@ -825,7 +825,7 @@ static int load_elf_library(struct file *file) MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, (elf_phdata->p_offset - ELF_PAGEOFFSET(elf_phdata->p_vaddr))); - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) goto out_free_ph; @@ -1203,15 +1203,15 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) pte_t *pte; pgd = pgd_offset(vma->vm_mm, addr); - pmd = pmd_alloc(pgd, addr); + pmd = pmd_offset(pgd, addr); if (!pmd) - goto end_coredump; - pte = pte_alloc(pmd, addr); + goto nextpage_coredump; + pte = pte_offset(pmd, addr); if (!pte) - goto end_coredump; - if (!pte_present(*pte) && - pte_none(*pte)) { + goto nextpage_coredump; + if (pte_none(*pte)) { +nextpage_coredump: DUMP_SEEK (file->f_pos + PAGE_SIZE); } else { DUMP_WRITE((void*)addr, PAGE_SIZE); diff --git a/fs/buffer.c b/fs/buffer.c index 6ca6f166b..c5cedb6e3 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1880,8 +1880,8 @@ int block_truncate_page(struct address_space *mapping, loff_t from, get_block_t iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); page = grab_cache_page(mapping, index); - err = PTR_ERR(page); - if (IS_ERR(page)) + err = -ENOMEM; + if (!page) goto out; if (!page->buffers) @@ -2750,7 +2750,7 @@ int kupdate(void *sem) tsk->session = 1; tsk->pgrp = 1; - strcpy(tsk->comm, "kupdate"); + strcpy(tsk->comm, "kupdated"); /* sigstop and sigcont will stop and wakeup kupdate */ spin_lock_irq(&tsk->sigmask_lock); diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 3cf258a23..4897e4ad1 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -141,6 +141,7 @@ static struct super_block * coda_read_super(struct super_block *sb, sb->s_magic = CODA_SUPER_MAGIC; sb->s_dev = dev; sb->s_op = &coda_super_operations; + sb->s_maxbytes = MAX_NON_LFS; /* get root fid from Venus: this needs the root inode */ error = venus_rootfid(sb, &fid); diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 3ce1b2e01..6c937c813 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -194,9 +194,9 @@ static struct super_block * cramfs_read_super(struct super_block *sb, void *data /* Set it all up.. */ sb->s_op = &cramfs_ops; - sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root)); + sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root)); + sb->s_maxbytes = MAX_NON_LFS; retval = sb; - out: return retval; } diff --git a/fs/dcache.c b/fs/dcache.c index 5ea250e56..30cd770fa 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -22,6 +22,7 @@ #include <linux/init.h> #include <linux/smp_lock.h> #include <linux/cache.h> +#include <linux/module.h> #include <asm/uaccess.h> @@ -223,8 +224,7 @@ static inline struct dentry * __dget_locked(struct dentry *dentry) atomic_inc(&dentry->d_count); if (atomic_read(&dentry->d_count) == 1) { dentry_stat.nr_unused--; - list_del(&dentry->d_lru); - INIT_LIST_HEAD(&dentry->d_lru); /* make "list_empty()" work */ + list_del_init(&dentry->d_lru); } return dentry; } @@ -413,8 +413,7 @@ repeat: if (atomic_read(&dentry->d_count)) continue; dentry_stat.nr_unused--; - list_del(tmp); - INIT_LIST_HEAD(tmp); + list_del_init(tmp); prune_one_dentry(dentry); goto repeat; } @@ -656,6 +655,7 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name) void d_instantiate(struct dentry *entry, struct inode * inode) { + if (!list_empty(&entry->d_alias)) BUG(); spin_lock(&dcache_lock); if (inode) list_add(&entry->d_alias, &inode->i_dentry); @@ -744,58 +744,48 @@ struct dentry * d_lookup(struct dentry * parent, struct qstr * name) /** * d_validate - verify dentry provided from insecure source - * @dentry: The dentry alleged to be valid - * @dparent: The parent dentry + * @dentry: The dentry alleged to be valid child of @dparent + * @dparent: The parent dentry (known to be valid) * @hash: Hash of the dentry * @len: Length of the name * * An insecure source has sent us a dentry, here we verify it and dget() it. * This is used by ncpfs in its readdir implementation. * Zero is returned in the dentry is invalid. - * - * NOTE: This function does _not_ dereference the pointers before we have - * validated them. We can test the pointer values, but we - * must not actually use them until we have found a valid - * copy of the pointer in kernel space.. */ -int d_validate(struct dentry *dentry, struct dentry *dparent, - unsigned int hash, unsigned int len) +int d_validate(struct dentry *dentry, struct dentry *dparent) { + unsigned long dent_addr = (unsigned long) dentry; + unsigned long min_addr = PAGE_OFFSET; + unsigned long align_mask = 0x0F; struct list_head *base, *lhp; - int valid = 1; - spin_lock(&dcache_lock); - if (dentry != dparent) { - base = d_hash(dparent, hash); - lhp = base; - while ((lhp = lhp->next) != base) { - if (dentry == list_entry(lhp, struct dentry, d_hash)) { - __dget_locked(dentry); - goto out; - } - } - } else { - /* - * Special case: local mount points don't live in - * the hashes, so we search the super blocks. - */ - struct super_block *sb = sb_entry(super_blocks.next); + if (dent_addr < min_addr) + goto out; + if (dent_addr > (unsigned long)high_memory - sizeof(struct dentry)) + goto out; + if (dent_addr & align_mask) + goto out; + if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 + + sizeof(struct dentry)))) + goto out; - for (; sb != sb_entry(&super_blocks); - sb = sb_entry(sb->s_list.next)) { - if (!sb->s_dev) - continue; - if (sb->s_root == dentry) { - __dget_locked(dentry); - goto out; - } + if (dentry->d_parent != dparent) + goto out; + + spin_lock(&dcache_lock); + lhp = base = d_hash(dparent, dentry->d_name.hash); + while ((lhp = lhp->next) != base) { + if (dentry == list_entry(lhp, struct dentry, d_hash)) { + __dget_locked(dentry); + spin_unlock(&dcache_lock); + return 1; } } - valid = 0; -out: spin_unlock(&dcache_lock); - return valid; +out: + return 0; } /* @@ -848,6 +838,7 @@ void d_delete(struct dentry * dentry) void d_rehash(struct dentry * entry) { struct list_head *list = d_hash(entry->d_parent, entry->d_name.hash); + if (!list_empty(&entry->d_hash)) BUG(); spin_lock(&dcache_lock); list_add(&entry->d_hash, list); spin_unlock(&dcache_lock); @@ -922,8 +913,7 @@ void d_move(struct dentry * dentry, struct dentry * target) list_add(&dentry->d_hash, &target->d_hash); /* Unhash the target: dput() will then get rid of it */ - list_del(&target->d_hash); - INIT_LIST_HEAD(&target->d_hash); + list_del_init(&target->d_hash); list_del(&dentry->d_child); list_del(&target->d_child); @@ -1250,6 +1240,7 @@ kmem_cache_t *dquot_cachep; /* SLAB cache for buffer_head structures */ kmem_cache_t *bh_cachep; +EXPORT_SYMBOL(bh_cachep); void __init vfs_caches_init(unsigned long mempages) { diff --git a/fs/efs/super.c b/fs/efs/super.c index 04b5fe91d..07398d6bb 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -178,6 +178,8 @@ struct super_block *efs_read_super(struct super_block *s, void *d, int silent) { s->s_magic = EFS_SUPER_MAGIC; s->s_blocksize = EFS_BLOCKSIZE; s->s_blocksize_bits = EFS_BLOCKSIZE_BITS; + s->s_maxbytes = MAX_NON_LFS; + if (!(s->s_flags & MS_RDONLY)) { #ifdef DEBUG printk(KERN_INFO "EFS: forcing read-only mode\n"); @@ -252,6 +252,8 @@ int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm) /* * This routine is used to map in a page into an address space: needed by * execve() for the initial stack and environment pages. + * + * tsk->mmap_sem is held for writing. */ void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address) { @@ -262,27 +264,29 @@ void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long a if (page_count(page) != 1) printk("mem_map disagrees with %p at %08lx\n", page, address); pgd = pgd_offset(tsk->mm, address); - pmd = pmd_alloc(pgd, address); - if (!pmd) { - __free_page(page); - force_sig(SIGKILL, tsk); - return; - } - pte = pte_alloc(pmd, address); - if (!pte) { - __free_page(page); - force_sig(SIGKILL, tsk); - return; - } - if (!pte_none(*pte)) { - pte_ERROR(*pte); - __free_page(page); - return; - } + + spin_lock(&tsk->mm->page_table_lock); + pmd = pmd_alloc(tsk->mm, pgd, address); + if (!pmd) + goto out; + pte = pte_alloc(tsk->mm, pmd, address); + if (!pte) + goto out; + if (!pte_none(*pte)) + goto out; flush_dcache_page(page); flush_page_to_ram(page); set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY)))); -/* no need for flush_tlb */ + tsk->mm->rss++; + spin_unlock(&tsk->mm->page_table_lock); + + /* no need for flush_tlb */ + return; +out: + spin_unlock(&tsk->mm->page_table_lock); + __free_page(page); + force_sig(SIGKILL, tsk); + return; } int setup_arg_pages(struct linux_binprm *bprm) @@ -302,7 +306,7 @@ int setup_arg_pages(struct linux_binprm *bprm) if (!mpnt) return -ENOMEM; - down(¤t->mm->mmap_sem); + down_write(¤t->mm->mmap_sem); { mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; @@ -321,12 +325,11 @@ int setup_arg_pages(struct linux_binprm *bprm) struct page *page = bprm->page[i]; if (page) { bprm->page[i] = NULL; - current->mm->rss++; put_dirty_page(current,page,stack_base); } stack_base += PAGE_SIZE; } - up(¤t->mm->mmap_sem); + up_write(¤t->mm->mmap_sem); return 0; } diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 9e4a9b6b0..c23a94d40 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -442,6 +442,7 @@ repeat: inode->u.ext2_i.i_file_acl = 0; inode->u.ext2_i.i_dir_acl = 0; inode->u.ext2_i.i_dtime = 0; + inode->u.ext2_i.i_prealloc_count = 0; inode->u.ext2_i.i_block_group = i; if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) inode->i_flags |= S_SYNC; diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index fd54c3040..2272fe393 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1047,6 +1047,7 @@ void ext2_read_inode (struct inode * inode) inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32; } inode->i_generation = le32_to_cpu(raw_inode->i_generation); + inode->u.ext2_i.i_prealloc_count = 0; inode->u.ext2_i.i_block_group = block_group; /* diff --git a/fs/hfs/super.c b/fs/hfs/super.c index a39710f09..a88a705a5 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -436,6 +436,7 @@ struct super_block *hfs_read_super(struct super_block *s, void *data, goto bail1; } + s->s_maxbytes = MAX_NON_LFS; s->s_magic = HFS_SUPER_MAGIC; s->s_blocksize_bits = HFS_SECTOR_SIZE_BITS; s->s_blocksize = HFS_SECTOR_SIZE; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index a5db0acd3..08ac66772 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -427,6 +427,7 @@ struct super_block *hpfs_read_super(struct super_block *s, void *options, s->s_blocksize = 512; s->s_blocksize_bits = 9; s->s_op = &hpfs_sops; + s->s_maxbytes = MAX_NON_LFS; s->s_hpfs_root = superblock->root; s->s_hpfs_fs_size = superblock->n_sectors; diff --git a/fs/inode.c b/fs/inode.c index 822e5187a..382e9ef97 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -133,7 +133,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) if (sb) { /* Don't do this for I_DIRTY_PAGES - that doesn't actually dirty the inode itself */ - if (flags & (I_DIRTY | I_DIRTY_SYNC)) { + if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) { if (sb->s_op && sb->s_op->dirty_inode) sb->s_op->dirty_inode(inode); } @@ -613,6 +613,7 @@ static void clean_inode(struct inode *inode) inode->i_bdev = NULL; inode->i_data.a_ops = &empty_aops; inode->i_data.host = inode; + inode->i_data.gfp_mask = GFP_HIGHUSER; inode->i_mapping = &inode->i_data; } diff --git a/fs/iobuf.c b/fs/iobuf.c index bcaa98826..540124355 100644 --- a/fs/iobuf.c +++ b/fs/iobuf.c @@ -55,7 +55,7 @@ int alloc_kiovec(int nr, struct kiobuf **bufp) return -ENOMEM; } kiobuf_init(iobuf); - *bufp++ = iobuf; + bufp[i] = iobuf; } return 0; diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 91f55dfb7..68741046a 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -663,6 +663,11 @@ root_found: s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */; + /* Set this for reference. Its not currently used except on write + which we don't have .. */ + + s->s_maxbytes = MAX_NON_LFS; + /* RDE: data zone now byte offset! */ first_data_zone = ((isonum_733 (rootp->extent) + diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index d044ef3a3..f80193e7d 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -10,8 +10,8 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * $Id: inode-v23.c,v 1.43 2000/08/22 08:00:22 dwmw2 Exp $ - * + * $Id: inode-v23.c,v 1.43.2.6 2001/01/09 00:32:48 dwmw2 Exp $ + * + sb_maxbytes / generic_file_open() fixes for 2.4.0-ac4 * * Ported to Linux 2.3.x and MTD: * Copyright (C) 2000 Alexander Larsson (alex@cendio.se), Cendio Systems AB @@ -84,6 +84,7 @@ jffs_read_super(struct super_block *sb, void *data, int silent) sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->u.generic_sbp = (void *) 0; + sb->s_maxbytes = 0xFFFFFFFF; /* Build the file system. */ if (jffs_build_fs(sb) < 0) { diff --git a/fs/minix/inode.c b/fs/minix/inode.c index d30699826..db6168073 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -259,6 +259,9 @@ static struct super_block *minix_read_super(struct super_block *s, void *data, minix_set_bit(0,s->u.minix_sb.s_imap[0]->b_data); minix_set_bit(0,s->u.minix_sb.s_zmap[0]->b_data); + + s->s_maxbytes = MAX_NON_LFS; + /* set up enough so that it can read an inode */ s->s_op = &minix_sops; root_inode = iget(s, MINIX_ROOT_INO); diff --git a/fs/namei.c b/fs/namei.c index 105833e4e..0f25265ac 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1013,7 +1013,7 @@ do_last: error = -ELOOP; if (flag & O_NOFOLLOW) goto exit_dput; - do __follow_down(&nd->mnt,&dentry); while(d_mountpoint(dentry)); + while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry)); } error = -ENOENT; if (!dentry->d_inode) @@ -1927,13 +1927,11 @@ out: * bloody create() on broken symlinks. Furrfu... */ name = __getname(); - if (IS_ERR(name)) - goto fail_name; + if (!name) + return -ENOMEM; strcpy(name, nd->last.name); nd->last.name = name; return 0; -fail_name: - link = name; fail: path_release(nd); return PTR_ERR(link); diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 92d0aaba1..25ac483a1 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -326,56 +326,15 @@ ncp_lookup_validate(struct dentry * dentry, int flags) return res; } -/* most parts from nfsd_d_validate() */ -static int -ncp_d_validate(struct dentry *dentry) -{ - unsigned long dent_addr = (unsigned long) dentry; - unsigned long min_addr = PAGE_OFFSET; - unsigned long align_mask = 0x0F; - unsigned int len; - int valid = 0; - - if (dent_addr < min_addr) - goto bad_addr; - if (dent_addr > (unsigned long)high_memory - sizeof(struct dentry)) - goto bad_addr; - if ((dent_addr & ~align_mask) != dent_addr) - goto bad_align; - if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 + - sizeof(struct dentry)))) - goto bad_addr; - /* - * Looks safe enough to dereference ... - */ - len = dentry->d_name.len; - if (len > NCP_MAXPATHLEN) - goto out; - /* - * Note: d_validate doesn't dereference the parent pointer ... - * just combines it with the name hash to find the hash chain. - */ - valid = d_validate(dentry, dentry->d_parent, dentry->d_name.hash, len); -out: - return valid; - -bad_addr: - PRINTK("ncp_d_validate: invalid address %lx\n", dent_addr); - goto out; -bad_align: - PRINTK("ncp_d_validate: unaligned address %lx\n", dent_addr); - goto out; -} - static struct dentry * ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) { struct dentry *dent = dentry; struct list_head *next; - if (ncp_d_validate(dent)) { - if (dent->d_parent == parent && - (unsigned long)dent->d_fsdata == fpos) { + if (d_validate(dent, parent)) { + if (dent->d_name.len <= NCP_MAXPATHLEN && + (unsigned long)dent->d_fsdata == fpos) { if (!dent->d_inode) { dput(dent); dent = NULL; @@ -580,6 +539,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, struct ncp_cache_control ctl = *ctrl; struct qstr qname; int valid = 0; + int hashed = 0; ino_t ino = 0; __u8 __name[256]; @@ -602,9 +562,11 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, newdent = d_alloc(dentry, &qname); if (!newdent) goto end_advance; - } else + } else { + hashed = 1; memcpy((char *) newdent->d_name.name, qname.name, newdent->d_name.len); + } if (!newdent->d_inode) { entry->opened = 0; @@ -612,7 +574,9 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, newino = ncp_iget(inode->i_sb, entry); if (newino) { newdent->d_op = &ncp_dentry_operations; - d_add(newdent, newino); + d_instantiate(newdent, newino); + if (!hashed) + d_rehash(newdent); } } else ncp_update_inode2(newdent->d_inode, entry); diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 6cb6e863f..d839cbf0d 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -327,6 +327,7 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent) else default_bufsize = 1024; + sb->s_maxbytes = MAX_NON_LFS; sb->s_blocksize = 1024; /* Eh... Is this correct? */ sb->s_blocksize_bits = 10; sb->s_magic = NCP_SUPER_MAGIC; diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c index 50f52119d..ed4153dd6 100644 --- a/fs/ncpfs/mmap.c +++ b/fs/ncpfs/mmap.c @@ -43,7 +43,7 @@ static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area, int bufsize; int pos; - page = alloc_page(GFP_HIGHMEM); /* ncpfs has nothing against GFP_HIGHMEM + page = alloc_page(GFP_HIGHUSER); /* ncpfs has nothing against high pages as long as recvmsg and memset works on it */ if (!page) return page; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c3a3a913e..35303cf20 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -321,7 +321,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, desc->page = NULL; } - page = page_cache_alloc(); + page = alloc_page(GFP_HIGHUSER); if (!page) { status = -ENOMEM; goto out; @@ -1097,6 +1097,10 @@ nfs_permission(struct inode *inode, int mask) if (!NFS_PROTO(inode)->access) goto out; + + if (error == -EROFS) + goto out; + /* * Trust UNIX mode bits except: * diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index a48e711f5..abd08eebc 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -434,6 +434,11 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent) if (server->namelen == 0 || server->namelen > maxlen) server->namelen = maxlen; + if(version == 2) + sb->s_maxbytes = MAX_NON_LFS; + else + sb->s_maxbytes = ~0ULL; /* Unlimited on NFSv3 */ + /* Fire up the writeback cache */ if (nfs_reqlist_alloc(server) < 0) { printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n"); diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 303792b58..896a978cd 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -196,7 +196,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, struct iattr *attr = &argp->attrs; struct inode *inode; struct dentry *dchild; - int nfserr, type, mode, rdonly = 0; + int nfserr, type, mode; dev_t rdev = NODEV; dprintk("nfsd: CREATE %s %s\n", @@ -207,13 +207,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, if (nfserr) goto done; /* must fh_put dirfhp even on error */ - /* Check for MAY_WRITE separately. */ - nfserr = nfsd_permission(dirfhp->fh_export, dirfhp->fh_dentry, - MAY_WRITE); - if (nfserr == nfserr_rofs) { - rdonly = 1; /* Non-fatal error for echo > /dev/null */ - } else if (nfserr) - goto done; + /* Check for MAY_WRITE in nfsd_create if necessary */ nfserr = nfserr_acces; if (!argp->len) @@ -257,10 +251,25 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, * else assume a file */ if (inode) { type = inode->i_mode & S_IFMT; - if (type == S_IFCHR || type == S_IFBLK) { + switch(type) { + case S_IFCHR: + case S_IFBLK: /* reserve rdev for later checking */ attr->ia_size = inode->i_rdev; attr->ia_valid |= ATTR_SIZE; + + /* FALLTHROUGH */ + case S_IFIFO: + /* this is probably a permission check.. + * at least IRIX implements perm checking on + * echo thing > device-special-file-or-pipe + * by does a CREATE with type==0 + */ + nfserr = nfsd_permission(newfhp->fh_export, + newfhp->fh_dentry, + MAY_WRITE); + if (nfserr && nfserr != nfserr_rofs) + goto out_unlock; } } else type = S_IFREG; @@ -273,11 +282,6 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, mode = 0; /* ??? */ } - /* This is for "echo > /dev/null" a la SunOS. Argh. */ - nfserr = nfserr_rofs; - if (rdonly && (!inode || type == S_IFREG)) - goto out_unlock; - attr->ia_valid |= ATTR_MODE; attr->ia_mode = mode; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index ae3cb8a48..0f68337d3 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -149,12 +149,8 @@ nfsd(struct svc_rqst *rqstp) /* Lock module and set up kernel thread */ MOD_INC_USE_COUNT; lock_kernel(); - exit_mm(current); - current->session = 1; - current->pgrp = 1; + daemonize(); sprintf(current->comm, "nfsd"); - current->fs->umask = 0; - current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; nfsdstats.th_cnt++; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 43fc14a4f..3d0c84007 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -737,27 +737,24 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, * nice and simple solution (IMHO), and it seems to * work:-) */ - if (EX_WGATHER(exp) && (atomic_read(&inode->i_writecount) > 1 - || (last_ino == inode->i_ino && last_dev == inode->i_dev))) { -#if 0 - interruptible_sleep_on_timeout(&inode->i_wait, 10 * HZ / 1000); -#else - dprintk("nfsd: write defer %d\n", current->pid); -/* FIXME: Olaf commented this out [gam3] */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((HZ+99)/100); - current->state = TASK_RUNNING; - dprintk("nfsd: write resume %d\n", current->pid); -#endif - } + if (EX_WGATHER(exp)) { + if (atomic_read(&inode->i_writecount) > 1 + || (last_ino == inode->i_ino && last_dev == inode->i_dev)) { + dprintk("nfsd: write defer %d\n", current->pid); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((HZ+99)/100); + current->state = TASK_RUNNING; + dprintk("nfsd: write resume %d\n", current->pid); + } - if (inode->i_state & I_DIRTY) { - dprintk("nfsd: write sync %d\n", current->pid); - nfsd_sync(&file); - } + if (inode->i_state & I_DIRTY) { + dprintk("nfsd: write sync %d\n", current->pid); + nfsd_sync(&file); + } #if 0 - wake_up(&inode->i_wait); + wake_up(&inode->i_wait); #endif + } last_ino = inode->i_ino; last_dev = inode->i_dev; } diff --git a/fs/proc/array.c b/fs/proc/array.c index e98061fa8..65d182add 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -181,7 +181,7 @@ static inline char * task_mem(struct mm_struct *mm, char *buffer) unsigned long data = 0, stack = 0; unsigned long exec = 0, lib = 0; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); for (vma = mm->mmap; vma; vma = vma->vm_next) { unsigned long len = (vma->vm_end - vma->vm_start) >> 10; if (!vma->vm_file) { @@ -212,7 +212,7 @@ static inline char * task_mem(struct mm_struct *mm, char *buffer) mm->rss << (PAGE_SHIFT-10), data - stack, stack, exec - lib, lib); - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); return buffer; } @@ -321,7 +321,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer) task_unlock(task); if (mm) { struct vm_area_struct *vma; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = mm->mmap; while (vma) { vsize += vma->vm_end - vma->vm_start; @@ -329,7 +329,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer) } eip = KSTK_EIP(task); esp = KSTK_ESP(task); - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); } wchan = get_wchan(task); @@ -484,7 +484,7 @@ int proc_pid_statm(struct task_struct *task, char * buffer) task_unlock(task); if (mm) { struct vm_area_struct * vma; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = mm->mmap; while (vma) { pgd_t *pgd = pgd_offset(mm, vma->vm_start); @@ -505,7 +505,7 @@ int proc_pid_statm(struct task_struct *task, char * buffer) drs += pages; vma = vma->vm_next; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); mmput(mm); } return sprintf(buffer,"%d %d %d %d %d %d %d\n", @@ -582,7 +582,7 @@ ssize_t proc_pid_read_maps (struct task_struct *task, struct file * file, char * column = *ppos & (MAPS_LINE_LENGTH-1); /* quickly go to line lineno */ - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); for (map = mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++) continue; @@ -644,9 +644,7 @@ ssize_t proc_pid_read_maps (struct task_struct *task, struct file * file, char * i = len-column; if (i > count) i = count; - up(&mm->mmap_sem); copy_to_user(destptr, line+column, i); /* may have slept */ - down(&mm->mmap_sem); destptr += i; count -= i; column += i; @@ -665,7 +663,7 @@ ssize_t proc_pid_read_maps (struct task_struct *task, struct file * file, char * if (volatile_task) break; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); /* encode f_pos */ *ppos = (lineno << MAPS_LINE_SHIFT) + column; diff --git a/fs/proc/base.c b/fs/proc/base.c index c1a960c5d..a25126e77 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -64,7 +64,7 @@ static int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfs task_unlock(task); if (!mm) goto out; - down(&mm->mmap_sem); + down_read(&mm->mmap_sem); vma = mm->mmap; while (vma) { if ((vma->vm_flags & VM_EXECUTABLE) && @@ -76,7 +76,7 @@ static int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfs } vma = vma->vm_next; } - up(&mm->mmap_sem); + up_read(&mm->mmap_sem); mmput(mm); out: return result; diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 3453bf88b..2e99938b1 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -188,6 +188,8 @@ struct super_block *proc_read_super(struct super_block *s,void *data, s->s_blocksize_bits = 10; s->s_magic = PROC_SUPER_MAGIC; s->s_op = &proc_sops; + s->s_maxbytes = MAX_NON_LFS; + root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); if (!root_inode) goto out_no_root; diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index d24f65b50..5863e45ac 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -293,8 +293,8 @@ static int kstat_read_proc(char *page, char **start, off_t off, "page %u %u\n" "swap %u %u\n" "intr %u", - kstat.pgpgin, - kstat.pgpgout, + kstat.pgpgin >> 1, + kstat.pgpgout >> 1, kstat.pswpin, kstat.pswpout, sum diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 490c3d047..b1e90e849 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -369,6 +369,7 @@ static struct super_block *qnx4_read_super(struct super_block *s, } s->s_op = &qnx4_sops; s->s_magic = QNX4_SUPER_MAGIC; + s->s_maxbytes = MAX_NON_LFS; #ifndef CONFIG_QNX4FS_RW s->s_flags |= MS_RDONLY; /* Yup, read-only yet */ #endif diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c index 48ca45c0c..ad184a145 100644 --- a/fs/reiserfs/dir.c +++ b/fs/reiserfs/dir.c @@ -51,6 +51,8 @@ int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, int datasync) { int windex ; struct reiserfs_transaction_handle th ; + lock_kernel(); + journal_begin(&th, dentry->d_inode->i_sb, 1) ; windex = push_journal_writer("dir_fsync") ; reiserfs_prepare_for_journal(th.t_super, SB_BUFFER_WITH_SB(th.t_super), 1) ; @@ -58,6 +60,8 @@ int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, int datasync) { pop_journal_writer(windex) ; journal_end_sync(&th, dentry->d_inode->i_sb, 1) ; + unlock_kernel(); + return ret ; } diff --git a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c index daa30b588..f050e24af 100644 --- a/fs/reiserfs/fix_node.c +++ b/fs/reiserfs/fix_node.c @@ -840,7 +840,7 @@ void free_buffers_in_tb ( /* Get new buffers for storing new nodes that are created while balancing. - * Returns: SCHEDULE_OCCURED - schedule occured while the function worked; + * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; * CARRY_ON - schedule didn't occur while the function worked; * NO_DISK_SPACE - no disk space. */ @@ -1077,7 +1077,7 @@ static void decrement_key (struct cpu_key * p_s_key) * Calculate left/right common parent of the current node and L[h]/R[h]. * Calculate left/right delimiting key position. * Returns: PATH_INCORRECT - path in the tree is not correct; - SCHEDULE_OCCURRED - schedule occured while the function worked; + SCHEDULE_OCCURRED - schedule occurred while the function worked; * CARRY_ON - schedule didn't occur while the function worked; */ static int get_far_parent (struct tree_balance * p_s_tb, @@ -1198,7 +1198,7 @@ static int get_far_parent (struct tree_balance * p_s_tb, * S[n_path_offset] and L[n_path_offset]/R[n_path_offset]: F[n_path_offset], FL[n_path_offset], * FR[n_path_offset], CFL[n_path_offset], CFR[n_path_offset]. * Calculate numbers of left and right delimiting keys position: lkey[n_path_offset], rkey[n_path_offset]. - * Returns: SCHEDULE_OCCURRED - schedule occured while the function worked; + * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; * CARRY_ON - schedule didn't occur while the function worked; */ static int get_parents (struct tree_balance * p_s_tb, int n_h) @@ -1340,7 +1340,7 @@ static inline int can_node_be_removed (int mode, int lfree, int sfree, int rfree * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste; - * Returns: 1 - schedule occured; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -1678,7 +1678,7 @@ static int ip_check_balance (struct tree_balance * tb, int h) * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste; - * Returns: 1 - schedule occured; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -1848,7 +1848,7 @@ static int dc_check_balance_internal (struct tree_balance * tb, int h) * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste; - * Returns: 1 - schedule occured; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -1951,7 +1951,7 @@ static int dc_check_balance_leaf (struct tree_balance * tb, int h) * h current level of the node; * inum item number in S[h]; * mode d - delete, c - cut. - * Returns: 1 - schedule occured; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -1985,7 +1985,7 @@ static int dc_check_balance (struct tree_balance * tb, int h) * h current level of the node; * inum item number in S[h]; * mode i - insert, p - paste, d - delete, c - cut. - * Returns: 1 - schedule occured; + * Returns: 1 - schedule occurred; * 0 - balancing for higher levels needed; * -1 - no balancing for higher levels needed; * -2 - no disk space. @@ -2075,7 +2075,7 @@ static int get_direct_parent( /* Using lnum[n_h] and rnum[n_h] we should determine what neighbors * of S[n_h] we * need in order to balance S[n_h], and get them if necessary. - * Returns: SCHEDULE_OCCURRED - schedule occured while the function worked; + * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; * CARRY_ON - schedule didn't occur while the function worked; */ static int get_neighbors( diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 12ab13894..323c36cd6 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -304,6 +304,7 @@ static int _get_block_create_0 (struct inode * inode, long block, char * p = NULL; int chars; int ret ; + int done = 0 ; unsigned long offset ; // prepare the key to look for the 'block'-th block of file @@ -355,6 +356,14 @@ research: return -ENOENT; } + /* if we've got a direct item, and the buffer was uptodate, + ** we don't want to pull data off disk again. skip to the + ** end, where we map the buffer and return + */ + if (buffer_uptodate(bh_result)) { + goto finished ; + } + // read file tail into part of page offset = (cpu_key_k_offset(&key) - 1) & (PAGE_CACHE_SIZE - 1) ; fs_gen = get_generation(inode->i_sb) ; @@ -375,8 +384,24 @@ research: if (!is_direct_le_ih (ih)) { BUG (); } - chars = le16_to_cpu (ih->ih_item_len) - path.pos_in_item; + /* make sure we don't read more bytes than actually exist in + ** the file. This can happen in odd cases where i_size isn't + ** correct, and when direct item padding results in a few + ** extra bytes at the end of the direct item + */ + if ((le_ih_k_offset(ih) + path.pos_in_item) > inode->i_size) + break ; + if ((le_ih_k_offset(ih) - 1 + ih_item_len(ih)) > inode->i_size) { + chars = inode->i_size - (le_ih_k_offset(ih) - 1) - path.pos_in_item; + done = 1 ; + } else { + chars = le16_to_cpu (ih->ih_item_len) - path.pos_in_item; + } memcpy (p, B_I_PITEM (bh, ih) + path.pos_in_item, chars); + + if (done) + break ; + p += chars; if (PATH_LAST_POSITION (&path) != (B_NR_ITEMS (bh) - 1)) @@ -395,16 +420,14 @@ research: ih = get_ih (&path); } while (1); +finished: pathrelse (&path); - - // FIXME: b_blocknr == 0 here. but b_data contains correct data - // from tail. ll_rw_block will skip uptodate buffers bh_result->b_blocknr = 0 ; bh_result->b_dev = inode->i_dev; mark_buffer_uptodate (bh_result, 1); bh_result->b_state |= (1UL << BH_Mapped); + flush_dcache_page(bh_result->b_page) ; kunmap(bh_result->b_page) ; - return 0; } @@ -476,8 +499,8 @@ static int convert_tail_for_hole(struct inode *inode, index = tail_offset >> PAGE_CACHE_SHIFT ; if (index != hole_page->index) { tail_page = grab_cache_page(inode->i_mapping, index) ; - retval = PTR_ERR(tail_page) ; - if (IS_ERR(tail_page)) { + retval = -ENOMEM; + if (!tail_page) { goto out ; } } else { @@ -771,6 +794,7 @@ int reiserfs_get_block (struct inode * inode, long block, ** flush unbh before the transaction commits */ reiserfs_add_page_to_flush_list(&th, inode, unbh) ; + mark_buffer_dirty(unbh) ; //inode->i_blocks += inode->i_sb->s_blocksize / 512; //mark_tail_converted (inode); @@ -1260,7 +1284,7 @@ static int reiserfs_new_directory (struct reiserfs_transaction_handle *th, retval = search_item (sb, &key, path); if (retval == IO_ERROR) { reiserfs_warning ("vs-13080: reiserfs_new_directory: " - "i/o failure occured creating new directory\n"); + "i/o failure occurred creating new directory\n"); return -EIO; } if (retval == ITEM_FOUND) { @@ -1296,7 +1320,7 @@ static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th, retval = search_item (sb, &key, path); if (retval == IO_ERROR) { reiserfs_warning ("vs-13080: reiserfs_new_symlinik: " - "i/o failure occured creating new symlink\n"); + "i/o failure occurred creating new symlink\n"); return -EIO; } if (retval == ITEM_FOUND) { @@ -1486,8 +1510,8 @@ static int grab_tail_page(struct inode *p_s_inode, return -ENOENT ; } page = grab_cache_page(p_s_inode->i_mapping, index) ; - error = PTR_ERR(page) ; - if (IS_ERR(page)) { + error = -ENOMEM ; + if (!page) { goto out ; } /* start within the page of the last block in the file */ @@ -1566,8 +1590,9 @@ void reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) { /* so, if page != NULL, we have a buffer head for the offset at ** the end of the file. if the bh is mapped, and bh->b_blocknr != 0, ** then we have an unformatted node. Otherwise, we have a direct item, - ** and no zeroing is required. We zero after the truncate, because the - ** truncate might pack the item anyway (it will unmap bh if it packs). + ** and no zeroing is required on disk. We zero after the truncate, + ** because the truncate might pack the item anyway + ** (it will unmap bh if it packs). */ prevent_flush_page_lock(page, p_s_inode) ; journal_begin(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 ) ; @@ -1577,7 +1602,7 @@ void reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) { journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 ) ; allow_flush_page_lock(page, p_s_inode) ; - if (page && buffer_mapped(bh) && bh->b_blocknr != 0) { + if (page) { length = offset & (blocksize - 1) ; /* if we are not on a block boundary */ if (length) { @@ -1585,14 +1610,14 @@ void reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) { memset((char *)kmap(page) + offset, 0, length) ; flush_dcache_page(page) ; kunmap(page) ; - mark_buffer_dirty(bh) ; + if (buffer_mapped(bh) && bh->b_blocknr != 0) { + mark_buffer_dirty(bh) ; + } } - } - - if (page) { UnlockPage(page) ; page_cache_release(page) ; } + return ; } @@ -1645,6 +1670,7 @@ research: goto out ; } set_block_dev_mapped(bh_result, le32_to_cpu(item[pos_in_item]), inode); + mark_buffer_uptodate(bh_result, 1); } else if (is_direct_le_ih(ih)) { char *p ; p = page_address(bh_result->b_page) ; @@ -1664,6 +1690,7 @@ research: journal_mark_dirty(&th, inode->i_sb, bh) ; bytes_copied += copy_size ; set_block_dev_mapped(bh_result, 0, inode); + mark_buffer_uptodate(bh_result, 1); /* are there still bytes left? */ if (bytes_copied < bh_result->b_size && diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c index 72054ce3a..c8761c2ed 100644 --- a/fs/reiserfs/ioctl.c +++ b/fs/reiserfs/ioctl.c @@ -77,8 +77,8 @@ int reiserfs_unpack (struct inode * inode, struct file * filp) */ index = inode->i_size >> PAGE_CACHE_SHIFT ; page = grab_cache_page(inode->i_mapping, index) ; - retval = PTR_ERR(page) ; - if (IS_ERR(page)) { + retval = -ENOMEM; + if (!page) { goto out ; } retval = reiserfs_prepare_write(NULL, page, write_from, blocksize) ; diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index f4b24b590..83c7cd8f4 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -734,7 +734,7 @@ int search_by_key (struct super_block * p_s_sb, return IO_ERROR; } - /* It is possible that schedule occured. We must check whether the key + /* It is possible that schedule occurred. We must check whether the key to search is still in the tree rooted from the current buffer. If not then repeat search from the root. */ if ( fs_changed (fs_gen, p_s_sb) && @@ -1438,7 +1438,6 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th, if ( p_s_un_bh ) { int off; - int block_off ; char *data ; /* We are in direct2indirect conversion, so move tail contents @@ -1452,7 +1451,8 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th, ** the unformatted node, which might schedule, meaning we'd have to ** loop all the way back up to the start of the while loop. ** - ** The unformatted node is prepared and logged after the do_balance. + ** The unformatted node must be dirtied later on. We can't be + ** sure here if the entire tail has been deleted yet. ** ** p_s_un_bh is from the page cache (all unformatted nodes are ** from the page cache) and might be a highmem page. So, we @@ -1463,25 +1463,13 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th, data = page_address(p_s_un_bh->b_page) ; off = ((le_ih_k_offset (&s_ih) - 1) & (PAGE_CACHE_SIZE - 1)); - block_off = off & (p_s_un_bh->b_size - 1) ; memcpy(data + off, B_I_PITEM(PATH_PLAST_BUFFER(p_s_path), &s_ih), n_ret_value); - - /* clear out the rest of the block past the end of the file. */ - if (block_off + n_ret_value < p_s_un_bh->b_size) { - memset(data + off + n_ret_value, 0, - p_s_un_bh->b_size - block_off - n_ret_value) ; - } } /* Perform balancing after all resources have been collected at once. */ do_balance(&s_del_balance, NULL, NULL, M_DELETE); - /* see comment above for why this is after the do_balance */ - if (p_s_un_bh) { - mark_buffer_dirty(p_s_un_bh) ; - } - /* Return deleted body length */ return n_ret_value; } @@ -1521,7 +1509,7 @@ static void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th, retval = search_item (th->t_super, &cpu_key, &path); if (retval == IO_ERROR) { reiserfs_warning ("vs-: reiserfs_delete_solid_item: " - "i/o failure occured trying to delete %K\n", &cpu_key); + "i/o failure occurred trying to delete %K\n", &cpu_key); break; } if (retval != ITEM_FOUND) { @@ -1869,7 +1857,7 @@ void reiserfs_do_truncate (struct reiserfs_transaction_handle *th, retval = search_for_position_by_key(p_s_inode->i_sb, &s_item_key, &s_search_path); if (retval == IO_ERROR) { reiserfs_warning ("vs-5657: reiserfs_do_truncate: " - "i/o failure occured trying to truncate %K\n", &s_item_key); + "i/o failure occurred trying to truncate %K\n", &s_item_key); return; } if (retval == POSITION_FOUND || retval == FILE_NOT_FOUND) { diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 9838a1dcd..2d35ffe4f 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1,5 +1,14 @@ /* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README + * + * Trivial changes by Alan Cox to add the LFS fixes + * + * Trivial Changes: + * Rights granted to Hans Reiser to redistribute under other terms providing + * he accepts all liability including but not limited to patent, fitness + * for purpose, and direct or indirect claims arising from failure to perform. + * + * NO WARRANTY */ #ifdef __KERNEL__ @@ -483,6 +492,7 @@ static int read_super_block (struct super_block * s, int size) SB_BUFFER_WITH_SB (s) = bh; SB_DISK_SUPER_BLOCK (s) = rs; s->s_op = &reiserfs_sops; + s->s_maxbytes = 0xFFFFFFFF; /* 4Gig */ return 0; } diff --git a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c index f8153be3b..6493bd800 100644 --- a/fs/reiserfs/tail_conversion.c +++ b/fs/reiserfs/tail_conversion.c @@ -32,6 +32,7 @@ int direct2indirect (struct reiserfs_transaction_handle *th, struct inode * inod struct super_block * sb = inode->i_sb; struct buffer_head *up_to_date_bh ; struct item_head * p_le_ih = PATH_PITEM_HEAD (path); + unsigned long total_tail = 0 ; struct cpu_key end_key; /* Key to search for the last byte of the converted item. */ struct item_head ind_ih; /* new indirect item to be inserted or @@ -121,11 +122,20 @@ int direct2indirect (struct reiserfs_transaction_handle *th, struct inode * inod n_retval = reiserfs_delete_item (th, path, &end_key, inode, up_to_date_bh) ; + total_tail += n_retval ; if (tail_size == n_retval) // done: file does not have direct items anymore break; } + /* if we've copied bytes from disk into the page, we need to zero + ** out the unused part of the block (it was not up to date before) + ** the page is still kmapped (by whoever called reiserfs_get_block) + */ + if (up_to_date_bh) { + unsigned pgoff = (tail_offset + total_tail - 1) & (PAGE_CACHE_SIZE - 1); + memset(page_address(unbh->b_page) + pgoff, 0, n_blk_size - total_tail) ; + } inode->u.reiserfs_i.i_first_direct_byte = U32_MAX; diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index 7edadf2ac..c9cdea972 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -110,6 +110,9 @@ romfs_read_super(struct super_block *s, void *data, int silent) set_blocksize(dev, ROMBSIZE); s->s_blocksize = ROMBSIZE; s->s_blocksize_bits = ROMBSBITS; + s->u.generic_sbp = (void *) 0; + s->s_maxbytes = 0xFFFFFFFF; + bh = bread(dev, 0, ROMBSIZE); if (!bh) { /* XXX merge with other printk? */ diff --git a/fs/smbfs/ChangeLog b/fs/smbfs/ChangeLog index 6ceae2331..5eeeb6829 100644 --- a/fs/smbfs/ChangeLog +++ b/fs/smbfs/ChangeLog @@ -1,9 +1,22 @@ ChangeLog for smbfs. +2001-03-06 Urban Widmark <urban@teststation.com> + + * cache.c: d_add on hashed dentries corrupts d_hash list and + causes loops in d_lookup. Inherited bug. :) + * inode.c: tail -f fix for non-readonly opened files + (related to the smb_proc_open change). + * inode.c: tail -f fix for fast size changes with the same mtime. + +2001-03-02 Michael Kockelkorn <m.kockelkorn@biodata.com> + + * proc.c: fix smb_proc_open to allow open being called more than once + with different modes (O_RDONLY -> O_WRONLY) without closing. + 2001-02-10 Urban Widmark <urban@teststation.com> - * dir.c: replace non-bigmem safe cache with cache code from ncpfs - and fix some other bigmem bugs in smbfs. + * dir.c, cache.c: replace non-bigmem safe cache with cache code + from ncpfs and fix some other bigmem bugs in smbfs. * inode.c: root dentry not properly initialized * proc.c, sock.c: adjust max parameters & max data to follow max_xmit lots of servers were having find_next trouble with this. diff --git a/fs/smbfs/cache.c b/fs/smbfs/cache.c index e3e9c044f..3dc17d229 100644 --- a/fs/smbfs/cache.c +++ b/fs/smbfs/cache.c @@ -48,6 +48,7 @@ out_unlock: UnlockPage(page); page_cache_release(page); out: + return; } /* @@ -71,47 +72,6 @@ smb_invalidate_dircache_entries(struct dentry *parent) spin_unlock(&dcache_lock); } - -static int -smb_d_validate(struct dentry *dentry) -{ - unsigned long dent_addr = (unsigned long) dentry; - unsigned long min_addr = PAGE_OFFSET; - unsigned long align_mask = 0x0F; - unsigned int len; - int valid = 0; - - if (dent_addr < min_addr) - goto bad_addr; - if (dent_addr > (unsigned long)high_memory - sizeof(struct dentry)) - goto bad_addr; - if ((dent_addr & ~align_mask) != dent_addr) - goto bad_align; - if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 + - sizeof(struct dentry)))) - goto bad_addr; - /* - * Looks safe enough to dereference ... - */ - len = dentry->d_name.len; - if (len > SMB_MAXPATHLEN) - goto out; - /* - * Note: d_validate doesn't dereference the parent pointer ... - * just combines it with the name hash to find the hash chain. - */ - valid = d_validate(dentry, dentry->d_parent, dentry->d_name.hash, len); -out: - return valid; - -bad_addr: - printk(KERN_ERR "smb_d_validate: invalid address %lx\n", dent_addr); - goto out; -bad_align: - printk(KERN_ERR "smb_d_validate: unaligned address %lx\n", dent_addr); - goto out; -} - /* * dget, but require that fpos and parent matches what the dentry contains. * dentry is not known to be a valid pointer at entry. @@ -122,8 +82,8 @@ smb_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) struct dentry *dent = dentry; struct list_head *next; - if (smb_d_validate(dent)) { - if (dent->d_parent == parent && + if (d_validate(dent, parent)) { + if (dent->d_name.len <= SMB_MAXPATHLEN && (unsigned long)dent->d_fsdata == fpos) { if (!dent->d_inode) { dput(dent); @@ -167,6 +127,7 @@ smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir, struct inode *newino, *inode = dentry->d_inode; struct smb_cache_control ctl = *ctrl; int valid = 0; + int hashed = 0; ino_t ino = 0; qname->hash = full_name_hash(qname->name, qname->len); @@ -181,9 +142,11 @@ smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir, newdent = d_alloc(dentry, qname); if (!newdent) goto end_advance; - } else + } else { + hashed = 1; memcpy((char *) newdent->d_name.name, qname->name, newdent->d_name.len); + } if (!newdent->d_inode) { smb_renew_times(newdent); @@ -191,7 +154,9 @@ smb_fill_cache(struct file *filp, void *dirent, filldir_t filldir, newino = smb_iget(inode->i_sb, entry); if (newino) { smb_new_dentry(newdent); - d_add(newdent, newino); + d_instantiate(newdent, newino); + if (!hashed) + d_rehash(newdent); } } else smb_set_inode_attr(newdent->d_inode, entry); diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 40ee12566..d86ce6de2 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -161,17 +161,15 @@ smb_refresh_inode(struct dentry *dentry) struct smb_fattr fattr; error = smb_proc_getattr(dentry, &fattr); - if (!error) - { + if (!error) { smb_renew_times(dentry); /* * Check whether the type part of the mode changed, * and don't update the attributes if it did. */ - if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) + if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) { smb_set_inode_attr(inode, &fattr); - else - { + } else { /* * Big trouble! The inode has become a new object, * so any operations attempted on it are invalid. @@ -212,18 +210,11 @@ smb_revalidate_inode(struct dentry *dentry) struct smb_sb_info *s = server_from_dentry(dentry); struct inode *inode = dentry->d_inode; time_t last_time; + loff_t last_sz; int error = 0; DEBUG1("smb_revalidate_inode\n"); - /* - * If this is a file opened with write permissions, - * the inode will be up-to-date. - */ lock_kernel(); - if (S_ISREG(inode->i_mode) && smb_is_open(inode)) { - if (inode->u.smbfs_i.access != SMB_O_RDONLY) - goto out; - } /* * Check whether we've recently refreshed the inode. @@ -236,11 +227,13 @@ smb_revalidate_inode(struct dentry *dentry) /* * Save the last modified time, then refresh the inode. - * (Note: a size change should have a different mtime.) + * (Note: a size change should have a different mtime, + * or same mtime but different size.) */ last_time = inode->i_mtime; + last_sz = inode->i_size; error = smb_refresh_inode(dentry); - if (error || inode->i_mtime != last_time) { + if (error || inode->i_mtime != last_time || inode->i_size != last_sz) { VERBOSE("%s/%s changed, old=%ld, new=%ld\n", DENTRY_PATH(dentry), (long) last_time, (long) inode->i_mtime); @@ -399,6 +392,7 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent) sb->s_magic = SMB_SUPER_MAGIC; sb->s_flags = 0; sb->s_op = &smb_sops; + sb->s_maxbytes = MAX_NON_LFS; /* client support missing */ sb->u.smbfs_sb.mnt = NULL; sb->u.smbfs_sb.sock_file = NULL; diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index 9bfdc90a0..4725ab70f 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -950,7 +950,10 @@ smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish) #if 0 /* FIXME: why is this code not in? below we fix it so that a caller wanting RO doesn't get RW. smb_revalidate_inode does some - optimization based on access mode. tail -f needs it to be correct. */ + optimization based on access mode. tail -f needs it to be correct. + + We must open rw since we don't do the open if called a second time + with different 'wish'. Is that not supported by smb servers? */ if (!(wish & (O_WRONLY | O_RDWR))) mode = read_only; #endif @@ -989,8 +992,6 @@ smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish) /* smb_vwv2 has mtime */ /* smb_vwv4 has size */ ino->u.smbfs_i.access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK); - if (!(wish & (O_WRONLY | O_RDWR))) - ino->u.smbfs_i.access = SMB_O_RDONLY; ino->u.smbfs_i.open = server->generation; out: @@ -1008,23 +1009,20 @@ smb_open(struct dentry *dentry, int wish) int result; result = -ENOENT; - if (!inode) - { + if (!inode) { printk(KERN_ERR "smb_open: no inode for dentry %s/%s\n", DENTRY_PATH(dentry)); goto out; } - if (!smb_is_open(inode)) - { + if (!smb_is_open(inode)) { struct smb_sb_info *server = SMB_SERVER(inode); smb_lock_server(server); result = 0; if (!smb_is_open(inode)) result = smb_proc_open(server, dentry, wish); smb_unlock_server(server); - if (result) - { + if (result) { PARANOIA("%s/%s open failed, result=%d\n", DENTRY_PATH(dentry), result); goto out; diff --git a/fs/super.c b/fs/super.c index 6482259ce..601e3d63f 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1412,6 +1412,8 @@ fs_out: return retval; fail: + if (fstype->fs_flags & FS_SINGLE) + put_filesystem(fstype); if (list_empty(&sb->s_mounts)) kill_super(sb, 0); goto unlock_out; diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 1fb7beaa8..0f3618512 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -365,6 +365,7 @@ static struct super_block *sysv_read_super(struct super_block *sb, panic("sysv fs: bad i-node size"); set_blocksize(dev,BLOCK_SIZE); sb->sv_block_base = 0; + sb->s_maxbytes = MAX_NON_LFS; /* Try to read Xenix superblock */ if ((bh = bread(dev, 1, BLOCK_SIZE)) != NULL) { diff --git a/fs/udf/super.c b/fs/udf/super.c index 1e089c0b1..a23159427 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1415,7 +1415,7 @@ udf_read_super(struct super_block *sb, void *options, int silent) iput(inode); goto error_out; } - + sb->s_maxbytes = ~0ULL; return sb; error_out: diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 360291513..091a5cd6c 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -489,6 +489,12 @@ struct super_block * ufs_read_super (struct super_block * sb, void * data, if (!uspi) goto failed; + /* Set a 2Gig file limit. Some UFS variants need to override + this but as I don't know which I'll let those in the know loosen + the rules */ + + sb->s_maxbytes = MAX_NON_LFS; + switch (sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) { case UFS_MOUNT_UFSTYPE_44BSD: UFSD(("ufstype=44bsd\n")) diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 183ccfb13..d154f58d1 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -160,7 +160,7 @@ next1: frag_to_free = tmp; free_count = uspi->s_fpb; } -next2: +next2:; } if (free_count > 0) @@ -261,7 +261,7 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, u32 * p) } inode->i_blocks -= uspi->s_nspb; mark_inode_dirty(inode); -next: +next:; } if (free_count > 0) { diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c index 93c6af317..0b4cd7f51 100644 --- a/fs/umsdos/emd.c +++ b/fs/umsdos/emd.c @@ -16,8 +16,7 @@ #include <linux/umsdos_fs.h> #include <linux/dcache.h> #include <linux/pagemap.h> - -#include <asm/delay.h> +#include <linux/delay.h> static void copy_entry(struct umsdos_dirent *p, struct umsdos_dirent *q) { |