#
# 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
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) {
-/* $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)
}
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));
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 */
* we want flushed.
*/
while(start < end) {
- sregs->sbuf_pflush = start;
+ *sbuf_pflush = start;
start += PAGE_SIZE;
}
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;
sg[sz--].dvma_addr = sbus_dvma_addr(start);
start &= PAGE_MASK;
while(start < end) {
- sregs->sbuf_pflush = start;
+ *sbuf_pflush = start;
start += PAGE_SIZE;
}
}
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 */
start &= PAGE_MASK;
while(start < end) {
- sregs->sbuf_pflush = start;
+ *sbuf_pflush = start;
start += PAGE_SIZE;
}
sz--;
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;
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;
}
if (CURRENT->cmd == READ)
memset(CURRENT->buffer, 0, len);
- else
+ else
set_bit(BH_Protected, &CURRENT->bh->b_state);
end_request(1);
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;
}
}
-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;
}
*/
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;
}
/* 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);
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
{
struct buffer_head * bh;
- recover_reusable_buffer_heads();
if (nr_unused_buffer_heads > NR_RESERVED) {
bh = unused_list;
unused_list = bh->b_next_free;
*/
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;
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
*/
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);
* 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--;
}
* 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;
}
* 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) {
BUG();
if (!buffer_uptodate(bh)) {
arr[nr++] = bh;
+ bh->b_count++;
}
}
} else { /* WRITE */
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);
* 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++;
}
}
-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)
inode->u.ext2_i.i_next_alloc_goal++;
}
- *err = 0; // -ENOSPC;
+ *err = 0;
b = block;
*created = 0;
if (block < EXT2_NDIR_BLOCKS) {
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
{
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;
+}
+
#include <asm/bitops.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
+#include <linux/smp_lock.h>
#include <stdarg.h>
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 */
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 */
(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 */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
- NULL, /* revalidate */
+ NULL /* revalidate */
};
const struct inode_operations hpfs_symlink_iops =
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
- NULL, /* revalidate */
+ NULL /* revalidate */
};
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;
+++ /dev/null
-/*
- * 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;
-}
#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
};
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)
#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))
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 *);