From e06171a8286236da3ef76b7cb715bfa165707c95 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:25:49 -0500 Subject: [PATCH] Import 2.3.9pre4 --- arch/i386/defconfig | 12 +- arch/sparc64/kernel/sys_sparc32.c | 1 - arch/sparc64/mm/init.c | 18 ++- drivers/block/ll_rw_blk.c | 7 +- drivers/block/raid5.c | 6 +- drivers/block/rd.c | 2 +- fs/buffer.c | 105 +++++++------- fs/ext2/file.c | 45 +++--- fs/ext2/inode.c | 2 +- fs/hpfs/Makefile | 2 +- fs/hpfs/file.c | 220 +++++++++++++----------------- fs/hpfs/hpfs_fn.h | 2 + fs/hpfs/inode.c | 13 +- fs/hpfs/mmap.c | 128 ----------------- include/linux/fs.h | 10 +- 15 files changed, 203 insertions(+), 370 deletions(-) delete mode 100644 fs/hpfs/mmap.c diff --git a/arch/i386/defconfig b/arch/i386/defconfig index b5ede650874a..856ceecf3a7f 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -314,17 +314,7 @@ CONFIG_82C710_MOUSE=y # # USB drivers - not for the faint of heart # -CONFIG_USB=y -CONFIG_USB_UHCI=y -# CONFIG_USB_OHCI is not set -# CONFIG_USB_OHCI_HCD is not set -CONFIG_USB_HUB=y -CONFIG_USB_MOUSE=y -CONFIG_USB_KBD=y -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_ACM is not set -# CONFIG_USB_PRINTER is not set -# CONFIG_USB_SCSI is not set +# CONFIG_USB is not set # # Filesystems diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index a4d6c7116bde..a680814ebe60 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -2834,7 +2834,6 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) bprm.dentry = dentry; bprm.filename = filename; bprm.sh_bang = 0; - bprm.java = 0; bprm.loader = 0; bprm.exec = 0; if ((bprm.argc = count32(argv)) < 0) { diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 6f3232d1d4c6..c7eeb066da6d 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.128 1999/05/25 16:53:24 jj Exp $ +/* $Id: init.c,v 1.129 1999/06/25 10:32:08 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -419,10 +419,12 @@ __u32 mmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus) } if (iommu->strbuf_enabled) { + volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush; + spin_lock_irqsave(&iommu->iommu_lock, flags); iommu->flushflag = 0; while(start < end) { - sregs->sbuf_pflush = start; + *sbuf_pflush = start; start += PAGE_SIZE; } sregs->sbuf_fsync = __pa(&(iommu->flushflag)); @@ -447,6 +449,8 @@ void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus) start &= PAGE_MASK; if (iommu->strbuf_enabled) { + volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush; + spin_lock_irqsave(&iommu->iommu_lock, flags); /* 1) Clear the flush flag word */ @@ -456,7 +460,7 @@ void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus) * we want flushed. */ while(start < end) { - sregs->sbuf_pflush = start; + *sbuf_pflush = start; start += PAGE_SIZE; } @@ -484,6 +488,8 @@ void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control; if (iommu->strbuf_enabled) { + volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush; + spin_lock_irqsave(&iommu->iommu_lock, flags); iommu->flushflag = 0; @@ -500,7 +506,7 @@ void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) sg[sz--].dvma_addr = sbus_dvma_addr(start); start &= PAGE_MASK; while(start < end) { - sregs->sbuf_pflush = start; + *sbuf_pflush = start; start += PAGE_SIZE; } } @@ -535,6 +541,8 @@ void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus unsigned long flags, tmp; if (iommu->strbuf_enabled) { + volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush; + spin_lock_irqsave(&iommu->iommu_lock, flags); /* 1) Clear the flush flag word */ @@ -549,7 +557,7 @@ void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus start &= PAGE_MASK; while(start < end) { - sregs->sbuf_pflush = start; + *sbuf_pflush = start; start += PAGE_SIZE; } sz--; diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 39f0aeadd353..851d6f598039 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -384,12 +384,9 @@ void make_request(int major,int rw, struct buffer_head * bh) count = bh->b_size >> 9; sector = bh->b_rsector; - /* Uhhuh.. Nasty dead-lock possible here.. */ - if (buffer_locked(bh)) + /* Only one thread can actually submit the I/O. */ + if (test_and_set_bit(BH_Lock, &bh->b_state)) return; - /* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */ - - lock_buffer(bh); if (blk_size[major]) { unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1; diff --git a/drivers/block/raid5.c b/drivers/block/raid5.c index 3c5701b3eae7..609cdaaf59b2 100644 --- a/drivers/block/raid5.c +++ b/drivers/block/raid5.c @@ -586,13 +586,15 @@ static void raid5_build_block (struct stripe_head *sh, struct buffer_head *bh, i b_data = ((volatile struct buffer_head *) bh)->b_data; memset (bh, 0, sizeof (struct buffer_head)); - init_buffer(bh, dev, block, raid5_end_request, sh); + init_buffer(bh, raid5_end_request, sh); + bh->b_dev = dev; + bh->b_blocknr = block; ((volatile struct buffer_head *) bh)->b_data = b_data; bh->b_rdev = raid_conf->disks[i].dev; bh->b_rsector = sh->sector; - bh->b_state = (1 << BH_Req); + bh->b_state = (1 << BH_Req) | (1 << BH_Allocated); bh->b_size = sh->size; bh->b_list = BUF_LOCKED; } diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 81ce11c49bb2..6c2768b27945 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -173,7 +173,7 @@ repeat: if (CURRENT->cmd == READ) memset(CURRENT->buffer, 0, len); - else + else set_bit(BH_Protected, &CURRENT->bh->b_state); end_request(1); diff --git a/fs/buffer.c b/fs/buffer.c index 5823ddeb034f..9c0a66db7bf8 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -71,7 +71,6 @@ static struct buffer_head * free_list[NR_SIZES] = {NULL, }; static kmem_cache_t *bh_cachep; static struct buffer_head * unused_list = NULL; -static struct buffer_head * reuse_list = NULL; static DECLARE_WAIT_QUEUE_HEAD(buffer_wait); static int nr_buffers = 0; @@ -671,13 +670,10 @@ static void refill_freelist(int size) } } -void init_buffer(struct buffer_head *bh, kdev_t dev, int block, - bh_end_io_t *handler, void *dev_id) +void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *dev_id) { bh->b_list = BUF_CLEAN; bh->b_flushtime = 0; - bh->b_dev = dev; - bh->b_blocknr = block; bh->b_end_io = handler; bh->b_dev_id = dev_id; } @@ -725,9 +721,10 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate) */ spin_lock_irqsave(&page_uptodate_lock, flags); unlock_buffer(bh); + bh->b_count--; tmp = bh->b_this_page; while (tmp != bh) { - if (buffer_locked(tmp)) + if (tmp->b_count && (tmp->b_end_io == end_buffer_io_async)) goto still_busy; tmp = tmp->b_this_page; } @@ -806,9 +803,11 @@ get_free: /* OK, FINALLY we know that this buffer is the only one of its kind, * and that it's unused (b_count=0), unlocked, and clean. */ - init_buffer(bh, dev, block, end_buffer_io_sync, NULL); + init_buffer(bh, end_buffer_io_sync, NULL); + bh->b_dev = dev; + bh->b_blocknr = block; bh->b_count = 1; - bh->b_state = 0; + bh->b_state = 1 << BH_Allocated; /* Insert the buffer into the regular lists */ insert_into_lru_list(bh); @@ -1042,35 +1041,6 @@ static void put_unused_buffer_head(struct buffer_head * bh) unused_list = bh; } -/* - * We can't put completed temporary IO buffer_heads directly onto the - * unused_list when they become unlocked, since the device driver - * end_request routines still expect access to the buffer_head's - * fields after the final unlock. So, the device driver puts them on - * the reuse_list instead once IO completes, and we recover these to - * the unused_list here. - * - * Note that we don't do a wakeup here, but return a flag indicating - * whether we got any buffer heads. A task ready to sleep can check - * the returned value, and any tasks already sleeping will have been - * awakened when the buffer heads were added to the reuse list. - */ -static inline int recover_reusable_buffer_heads(void) -{ - struct buffer_head *head = xchg(&reuse_list, NULL); - int found = 0; - - if (head) { - do { - struct buffer_head *bh = head; - head = head->b_next_free; - put_unused_buffer_head(bh); - } while (head); - found = 1; - } - return found; -} - /* * Reserve NR_RESERVED buffer heads for async IO requests to avoid * no-buffer-head deadlock. Return NULL on failure; waiting for @@ -1080,7 +1050,6 @@ static struct buffer_head * get_unused_buffer_head(int async) { struct buffer_head * bh; - recover_reusable_buffer_heads(); if (nr_unused_buffer_heads > NR_RESERVED) { bh = unused_list; unused_list = bh->b_next_free; @@ -1204,8 +1173,10 @@ no_grow: */ add_wait_queue(&buffer_wait, &wait); current->state = TASK_UNINTERRUPTIBLE; - if (!recover_reusable_buffer_heads()) + if (nr_unused_buffer_heads < MAX_BUF_PER_PAGE) { + current->policy |= SCHED_YIELD; schedule(); + } remove_wait_queue(&buffer_wait, &wait); current->state = TASK_RUNNING; goto try_again; @@ -1237,7 +1208,9 @@ static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], i block = *(b++); tail = bh; - init_buffer(bh, dev, block, end_buffer_io_async, NULL); + init_buffer(bh, end_buffer_io_async, NULL); + bh->b_dev = dev; + bh->b_blocknr = block; /* * When we use bmap, we define block zero to represent @@ -1247,7 +1220,10 @@ static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], i */ if (bmap && !block) { memset(bh->b_data, 0, size); + set_bit(BH_Uptodate, &bh->b_state); + continue; } + set_bit(BH_Allocated, &bh->b_state); } tail->b_this_page = head; get_page(page); @@ -1283,13 +1259,14 @@ int block_flushpage(struct inode *inode, struct page *page, unsigned long offset * is this block fully flushed? */ if (offset <= curr_off) { - if (bh->b_blocknr) { + if (buffer_allocated(bh)) { bh->b_count++; wait_on_buffer(bh); if (bh->b_dev == B_FREE) BUG(); mark_buffer_clean(bh); clear_bit(BH_Uptodate, &bh->b_state); + clear_bit(BH_Allocated, &bh->b_state); bh->b_blocknr = 0; bh->b_count--; } @@ -1381,8 +1358,8 @@ int block_write_full_page (struct file *file, struct page *page, fs_getblock_t f * decisions (block #0 may actually be a valid block) */ bh->b_end_io = end_buffer_io_sync; - if (!buffer_uptodate(bh)) { - err = fs_get_block(inode, block, bh, 0); + if (!buffer_allocated(bh)) { + err = fs_get_block(inode, block, bh, FS_GETBLK_ALLOCATE); if (err) goto out; } @@ -1470,14 +1447,27 @@ int block_write_partial_page (struct file *file, struct page *page, unsigned lon * not going to fill it completely. */ bh->b_end_io = end_buffer_io_sync; - if (!buffer_uptodate(bh)) { - int update = start_offset || (end_bytes && (i == end_block)); - - err = fs_get_block(inode, block, bh, update); + if (!buffer_allocated(bh)) { + unsigned int flags = FS_GETBLK_ALLOCATE; + if (start_offset || (end_bytes && (i == end_block))) + flags |= FS_GETBLK_UPDATE; + err = fs_get_block(inode, block, bh, flags); if (err) goto out; } + if (start_offset || (end_bytes && (i == end_block))) { + if (!buffer_uptodate(bh)) { + lock_kernel(); + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + unlock_kernel(); + err = -EIO; + if (!buffer_uptodate(bh)) + goto out; + } + } + err = -EFAULT; len = blocksize; if (start_offset) { @@ -1586,6 +1576,7 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap) BUG(); if (!buffer_uptodate(bh)) { arr[nr++] = bh; + bh->b_count++; } } } else { /* WRITE */ @@ -1600,6 +1591,7 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap) set_bit(BH_Uptodate, &bh->b_state); set_bit(BH_Dirty, &bh->b_state); arr[nr++] = bh; + bh->b_count++; } bh = bh->b_this_page; } while (bh != head); @@ -1680,23 +1672,30 @@ int block_read_full_page(struct file * file, struct page * page) * their bnr cached but had an IO error! */ if (!buffer_uptodate(bh)) { - phys_block = inode->i_op->bmap(inode, iblock); + unsigned long phys_block = bh->b_blocknr; + if (!buffer_allocated(bh)) { + phys_block = inode->i_op->bmap(inode, iblock); + if (phys_block) { + bh->b_dev = inode->i_dev; + bh->b_blocknr = phys_block; + set_bit(BH_Allocated, &bh->b_state); + } + } + /* * this is safe to do because we hold the page lock: */ if (phys_block) { - init_buffer(bh, inode->i_dev, phys_block, end_buffer_io_async, NULL); + init_buffer(bh, end_buffer_io_async, NULL); arr[nr] = bh; + bh->b_count++; nr++; } else { /* * filesystem 'hole' represents zero-contents. - * - * Don't mark the buffer up-to-date (that also implies - * that it is ok on disk, which it isn't), but _do_ - * zero out the contents so that readers see the zeroes. */ memset(bh->b_data, 0, blocksize); + set_bit(BH_Uptodate, &bh->b_state); } } iblock++; diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 02a3c1d97a27..d78181b2b28a 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -106,41 +106,32 @@ static inline void remove_suid(struct inode *inode) } } -static int ext2_get_block(struct inode *inode, unsigned long block, struct buffer_head *bh, int update) +static int ext2_get_block(struct inode *inode, unsigned long block, struct buffer_head *bh, unsigned int flags) { - if (!bh->b_blocknr) { - int error, created; - unsigned long blocknr; - - blocknr = ext2_getblk_block(inode, block, 1, &error, &created); - if (!blocknr) { - if (!error) - error = -ENOSPC; - return error; - } + int error, created; + unsigned long blocknr; - bh->b_dev = inode->i_dev; - bh->b_blocknr = blocknr; + blocknr = ext2_getblk_block(inode, block, flags & FS_GETBLK_ALLOCATE, &error, &created); + if (!blocknr) { + if (error) + return error; + if (!(flags & FS_GETBLK_ALLOCATE)) + goto clear_and_uptodate; + return -ENOSPC; + } - if (!update) - return 0; + bh->b_dev = inode->i_dev; + bh->b_blocknr = blocknr; + set_bit(BH_Allocated, &bh->b_state); - if (created) { + if (created) { +clear_and_uptodate: + if (flags & FS_GETBLK_UPDATE) { memset(bh->b_data, 0, bh->b_size); set_bit(BH_Uptodate, &bh->b_state); - return 0; } } - - if (!update) - return 0; - - lock_kernel(); - ll_rw_block(READ, 1, &bh); - wait_on_buffer(bh); - unlock_kernel(); - - return buffer_uptodate(bh) ? 0 : -EIO; + return 0; } static int ext2_writepage (struct file * file, struct page * page) diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index d808fc3062c9..db80ff3649db 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -501,7 +501,7 @@ int ext2_getblk_block (struct inode * inode, long block, inode->u.ext2_i.i_next_alloc_goal++; } - *err = 0; // -ENOSPC; + *err = 0; b = block; *created = 0; if (block < EXT2_NDIR_BLOCKS) { diff --git a/fs/hpfs/Makefile b/fs/hpfs/Makefile index 46f1ffae02b1..2ebaece024b6 100644 --- a/fs/hpfs/Makefile +++ b/fs/hpfs/Makefile @@ -1,5 +1,5 @@ O_TARGET := hpfs.o -O_OBJS := alloc.o anode.o buffer.o dentry.o dir.o dnode.o ea.o file.o inode.o map.o mmap.o name.o namei.o super.o +O_OBJS := alloc.o anode.o buffer.o dentry.o dir.o dnode.o ea.o file.o inode.o map.o name.o namei.o super.o M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index 7cea8dcdc099..88bd8b886976 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -53,143 +53,111 @@ void hpfs_truncate(struct inode *i) { if (IS_IMMUTABLE(i)) return /*-EPERM*/; i->i_hpfs_n_secs = 0; - hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9)); i->i_blocks = 1 + ((i->i_size + 511) >> 9); + hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9)); hpfs_write_inode(i); } -ssize_t hpfs_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos) +int hpfs_getblk_block(struct inode *inode, long block, int create, int *err, int *created) { - struct inode *inode = filp->f_dentry->d_inode; - int i,j; - int a = generic_file_read(filp, buf, count, ppos); - if (inode->i_hpfs_conv != CONV_TEXT || a < 0) { - return a; - } - for (i = 0, j = 0; i < a; i++) { - char c; - int error; - if ((error = get_user(c, buf + i))) return error; - if (c != '\r') { - if (i != j) put_user(c, buf + j); - j++; + int add; + int sec = 0; + down(&inode->i_sem); + if (err) *err = 0; + if (created) *created = 0; + if (!inode->i_blocks) { + hpfs_error(inode->i_sb, "hpfs_get_block: inode %08x has no blocks", inode->i_ino); + if (err) *err = -EFSERROR; + up(&inode->i_sem); + return 0; + } + if (block < ((add = inode->i_blocks - 1))) { + int bm; + if (!(bm = hpfs_bmap(inode, block))) { + hpfs_error(inode->i_sb, "hpfs_get_block: cound not bmap block %08x, inode %08x, size %08x", (int)block, inode->i_ino, (int)inode->i_size); + *err = -EFSERROR; } + up(&inode->i_sem); + return bm; + } + if (!create) { + if (err) *err = -EFBIG; + up(&inode->i_sem); + return 0; } - return j; + if (created) *created = 1; + while (add <= block) { + if ((sec = hpfs_add_sector_to_btree(inode->i_sb, inode->i_ino, 1, add)) == -1) { + if (err) *err = -ENOSPC; + hpfs_truncate_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1); + return 0; + } /* FIXME: clear block */ + add++; + } + inode->i_blocks = add + 1; + up(&inode->i_sem); + return sec; } -ssize_t hpfs_file_write(struct file *filp, const char *buf, size_t count, - loff_t *ppos) +/* copied from ext2fs */ +static int hpfs_get_block(struct inode *inode, unsigned long block, struct buffer_head *bh, int update) { - struct inode *i = filp->f_dentry->d_inode; - int carry, error = 0; - const char *start = buf; - if (!i) return -EINVAL; - if (!S_ISREG(i->i_mode)) return -EINVAL; - if (IS_IMMUTABLE(i)) return -EPERM; - if (filp->f_flags & O_APPEND) *ppos = i->i_size; - if (count <= 0) return 0; - if ((unsigned)(*ppos+count) >= 0x80000000U || (unsigned)count >= 0x80000000U) return -EFBIG; - carry = 0; - while (count || carry) { - int ii, add = 0; - secno sec = 0; /* Go away, uninitialized variable warning */ - int offset, size, written; - char ch; - struct buffer_head *bh; - char *data; - offset = *ppos & 0x1ff; - size = count > 0x200 - offset ? 0x200 - offset : count; - if ((*ppos >> 9) < ((i->i_size + 0x1ff) >> 9)) { - i->i_hpfs_n_secs = 0; - if (!(sec = hpfs_bmap(i, *ppos >> 9))) { - hpfs_error(i->i_sb, "bmap failed, file %08x, fsec %08x", - i->i_ino, *ppos >> 9); - error =- EFSERROR; - break; - } - } else for (ii = (i->i_size + 0x1ff) >> 9, add = 1; ii <= *ppos >> 9; ii++) { - if ((sec = hpfs_add_sector_to_btree(i->i_sb, i->i_ino, 1, ii)) == -1) { - hpfs_truncate(i); - return -ENOSPC; - } - if (*ppos != i->i_size) - if ((data = hpfs_get_sector(i->i_sb, sec, &bh))) { - memset(data, 0, 512); - mark_buffer_dirty(bh, 0); - brelse(bh); - } - i->i_size = 0x200 * ii + 1; - i->i_blocks++; - /*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1; - if (i->i_sb->s_hpfs_chk >= 2) { - secno bsec; - bsec = hpfs_bmap(i, ii); - if (sec != bsec) { - hpfs_error(i->i_sb, "sec == %08x, bmap returns %08x", sec, bsec); - error = -EFSERROR; - break; - } - } - PRINTK(("file_write: added %08x\n", sec)); - } - if (!sec || sec == 15) { - hpfs_error(i->i_sb, "bmap returned empty sector"); - error = -EFSERROR; - break; - } - if (i->i_sb->s_hpfs_chk) - if (hpfs_chk_sectors(i->i_sb, sec, 1, "data")) { - error = -EFSERROR; - break; - } - if ((!offset && size == 0x200) || add) - data = hpfs_get_sector(i->i_sb, sec, &bh); - else data = hpfs_map_sector(i->i_sb, sec, &bh, 0); - if (!data) { - error = -EIO; - break; - } - if (i->i_hpfs_conv != CONV_TEXT) { - memcpy_fromfs(data + offset, buf, written = size); - buf += size; - } else { - int left; - char *to; - /* LF->CR/LF conversion, stolen from fat fs */ - written = left = 0x200 - offset; - to = (char *) bh->b_data + (*ppos & 0x1ff); - if (carry) { - *to++ = '\n'; - left--; - carry = 0; - } - for (size = 0; size < count && left; size++) { - if ((error = get_user(ch, buf++))) break; - if (ch == '\n') { - *to++ = '\r'; - left--; - } - if (!left) carry = 1; - else { - *to++ = ch; - left--; - } - } - written -= left; + if (!bh->b_blocknr) { + int error, created; + unsigned long blocknr; + + blocknr = hpfs_getblk_block(inode, block, 1, &error, &created); + if (!blocknr) { + if (!error) + error = -ENOSPC; + return error; } - update_vm_cache(i, *ppos, bh->b_data + (*ppos & 0x1ff), written); - *ppos += written; - if (*ppos > i->i_size) { - i->i_size = *ppos; - /*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1; + + bh->b_dev = inode->i_dev; + bh->b_blocknr = blocknr; + + if (!update) + return 0; + + if (created) { + memset(bh->b_data, 0, bh->b_size); + set_bit(BH_Uptodate, &bh->b_state); + return 0; } - mark_buffer_dirty(bh, 0); - brelse(bh); - count -= size; } - if (start == buf) return error; - i->i_mtime = CURRENT_TIME; - /*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1; - return buf - start; + + if (!update) + return 0; + + lock_kernel(); + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + unlock_kernel(); + + return buffer_uptodate(bh) ? 0 : -EIO; +} + +int hpfs_writepage(struct file *file, struct page *page) +{ + return block_write_full_page(file, page, hpfs_get_block); +} + +long hpfs_write_one_page (struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char *buf) +{ + return block_write_partial_page(file, page, offset, bytes, buf, hpfs_get_block); } + + +ssize_t hpfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + ssize_t retval; + struct inode *inode = file->f_dentry->d_inode; + retval = generic_file_write(file, buf, count, ppos, hpfs_write_one_page); + if (retval > 0) { + /*remove_suid(inode);*/ + inode->i_mtime = CURRENT_TIME; + inode->i_hpfs_dirty = 1; + } + return retval; +} + diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index cdb2c709e495..050b63597b17 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -259,6 +260,7 @@ secno hpfs_bmap(struct inode *, unsigned); void hpfs_truncate(struct inode *); ssize_t hpfs_file_read(struct file *, char *, size_t, loff_t *); ssize_t hpfs_file_write(struct file *, const char *, size_t, loff_t *); +int hpfs_writepage (struct file *, struct page *); /* inode.c */ diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 111b416d9204..b3132c450f58 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -11,7 +11,7 @@ static const struct file_operations hpfs_file_ops = { NULL, /* lseek - default */ - hpfs_file_read, /* read */ + generic_file_read, /* read */ hpfs_file_write, /* write */ NULL, /* readdir - bad */ NULL, /* poll - default */ @@ -44,9 +44,9 @@ static const struct inode_operations hpfs_file_iops = (int (*)(struct inode *, int)) &hpfs_bmap, /* bmap */ block_read_full_page, /* readpage */ - NULL, /* writepage */ - NULL, /* flushpage */ - &hpfs_truncate, /* truncate */ + hpfs_writepage, /* writepage */ + block_flushpage, /* flushpage */ + hpfs_truncate, /* truncate */ NULL, /* permission */ NULL, /* smap */ NULL, /* revalidate */ @@ -92,7 +92,7 @@ static const struct inode_operations hpfs_dir_iops = NULL, /* truncate */ NULL, /* permission */ NULL, /* smap */ - NULL, /* revalidate */ + NULL /* revalidate */ }; const struct inode_operations hpfs_symlink_iops = @@ -116,7 +116,7 @@ const struct inode_operations hpfs_symlink_iops = NULL, /* truncate */ NULL, /* permission */ NULL, /* smap */ - NULL, /* revalidate */ + NULL /* revalidate */ }; @@ -128,7 +128,6 @@ void hpfs_read_inode(struct inode *i) unsigned char *ea; int ea_size; i->i_op = 0; - /*i->i_hpfs_sem = MUTEX;*/ init_MUTEX(&i->i_hpfs_sem); i->i_uid = sb->s_hpfs_uid; i->i_gid = sb->s_hpfs_gid; diff --git a/fs/hpfs/mmap.c b/fs/hpfs/mmap.c deleted file mode 100644 index 3fd5446647d8..000000000000 --- a/fs/hpfs/mmap.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * linux/fs/hpfs/mmap.c - * - * taken from fat filesystem - * - * Written by Jacques Gelinas (jacques@solucorp.qc.ca) - * Inspired by fs/nfs/mmap.c (Jon Tombs 15 Aug 1993) - * - * Modified for HPFS by Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz) - * - * mmap handling for hpfs filesystem - * (generic_file_mmap may be used only on filesystems that keep zeros - * in last file sector beyond end) - */ - -/* - * generic_file_mmap doesn't erase the space beyond file end in last sector. :-( - * Hpfs doesn't keep zeros in last sector. This causes problems with kernel - * mkdep.c and probably other programs. Additionally this could be a security - * hole - some interesting data, like pieces of /etc/shadow could be found - * beyond file end. - * - * So, I can't use generic mmap. mmap from fat filesystem looks good, so I used - * it. - * - * BTW. fat uses generic mmap on normal disks. Doesn't it also have above bugs? - * I don't think Msdos erases space in last sector. - * - * If you fix generic_file_mmap, you can remove this file and use it. - */ - -#include "hpfs_fn.h" - -/* - * Fill in the supplied page for mmap - */ - -static unsigned long hpfs_file_mmap_nopage( - struct vm_area_struct * area, - unsigned long address, - int error_code) -{ - /*struct inode * inode = area->vm_inode;*/ - struct inode * inode = area->vm_file->f_dentry->d_inode; - unsigned long page; - unsigned int clear; - loff_t pos; - long gap; /* distance from eof to pos */ - - page = __get_free_page(GFP_KERNEL); - if (!page) - return page; - address &= PAGE_MASK; - pos = address - area->vm_start + area->vm_offset; - - clear = 0; - gap = inode->i_size - pos; - if (gap <= 0){ - /* mmaping beyond end of file */ - clear = PAGE_SIZE; - }else{ - int cur_read; - int need_read; - /*struct file *filp = area->vm_file;*/ - struct file filp; - if (gap < PAGE_SIZE){ - clear = PAGE_SIZE - gap; - } - filp.f_reada = 0; - filp.f_pos = pos; - filp.f_dentry=area->vm_file->f_dentry; - need_read = PAGE_SIZE - clear; - { - mm_segment_t cur_fs = get_fs(); - set_fs (KERNEL_DS); - cur_read = generic_file_read (&filp,(char*)page - ,need_read,&pos); - set_fs (cur_fs); - } - if (cur_read != need_read){ - hpfs_error(inode->i_sb, "Error while reading an mmap file %08x", inode->i_ino); - } - } - if (clear > 0){ - memset ((char*)page+PAGE_SIZE-clear,0,clear); - } - return page; -} - -struct vm_operations_struct hpfs_file_mmap = { - NULL, /* open */ - NULL, /* close */ - NULL, /* unmap */ - NULL, /* protect */ - NULL, /* sync */ - NULL, /* advise */ - hpfs_file_mmap_nopage, /* nopage */ - NULL, /* wppage */ - NULL, /* swapout */ - NULL, /* swapin */ -}; - -/* - * This is used for a general mmap of an msdos file - * Returns 0 if ok, or a negative error code if not. - */ -int hpfs_mmap(struct file * file, struct vm_area_struct * vma) -{ - struct inode *inode = file->f_dentry->d_inode; - /*printk("start mmap\n");*/ - if (vma->vm_flags & VM_SHARED) /* only PAGE_COW or read-only supported now */ - return -EINVAL; - if (vma->vm_offset & (inode->i_sb->s_blocksize - 1)) - return -EINVAL; - if (!inode->i_sb || !S_ISREG(inode->i_mode)) - return -EACCES; - /*if (!IS_RDONLY(inode)) { - inode->i_atime = CURRENT_TIME; - mark_inode_dirty(inode); - }*/ - - vma->vm_file = file; - /*inode->i_count++;*/ - file->f_count++; - vma->vm_ops = &hpfs_file_mmap; - /*printk("end mmap\n");*/ - return 0; -} diff --git a/include/linux/fs.h b/include/linux/fs.h index 0f664ed041da..89697693ed20 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -188,7 +188,9 @@ typedef char buffer_block[BLOCK_SIZE]; #define BH_Dirty 1 /* 1 if the buffer is dirty */ #define BH_Lock 2 /* 1 if the buffer is locked */ #define BH_Req 3 /* 0 if the buffer has been invalidated */ +#define BH_Allocated 4 /* 1 if the buffer has allocated backing store */ #define BH_Protected 6 /* 1 if the buffer is protected */ + /* * Try to keep the most commonly used fields in single cache lines (16 * bytes) to improve performance. This ordering should be @@ -232,7 +234,7 @@ struct buffer_head { }; typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate); -void init_buffer(struct buffer_head *, kdev_t, int, bh_end_io_t *, void *); +void init_buffer(struct buffer_head *, bh_end_io_t *, void *); #define __buffer_state(bh, state) (((bh)->b_state & (1UL << BH_##state)) != 0) @@ -240,6 +242,7 @@ void init_buffer(struct buffer_head *, kdev_t, int, bh_end_io_t *, void *); #define buffer_dirty(bh) __buffer_state(bh,Dirty) #define buffer_locked(bh) __buffer_state(bh,Lock) #define buffer_req(bh) __buffer_state(bh,Req) +#define buffer_allocated(bh) __buffer_state(bh,Allocated) #define buffer_protected(bh) __buffer_state(bh,Protected) #define buffer_page(bh) (mem_map + MAP_NR((bh)->b_data)) @@ -870,7 +873,10 @@ extern struct buffer_head * breada(kdev_t, int, int, unsigned int, unsigned int) extern int brw_page(int, struct page *, kdev_t, int [], int, int); typedef long (*writepage_t)(struct file *, struct page *, unsigned long, unsigned long, const char *); -typedef int (*fs_getblock_t)(struct inode *, unsigned long, struct buffer_head *, int); +typedef int (*fs_getblock_t)(struct inode *, unsigned long, struct buffer_head *, unsigned int); + +#define FS_GETBLK_ALLOCATE 1 +#define FS_GETBLK_UPDATE 2 /* Generic buffer handling for block filesystems.. */ extern int block_read_full_page(struct file *, struct page *); -- 2.39.5