--- arch/alpha/kernel/entry.S.~1~ Mon Dec 7 23:11:00 1998 +++ arch/alpha/kernel/entry.S Mon Dec 7 23:11:05 1998 @@ -10,7 +10,7 @@ #define rti .long PAL_rti #define SIGCHLD 20 -#define NR_SYSCALLS 370 +#define NR_SYSCALLS 371 #define osf_vfork sys_fork /* @@ -1127,4 +1127,5 @@ .quad sys_getcwd .quad sys_capget .quad sys_capset - .quad sys_ni_syscall /* 370 */ + .quad sys_fsattr /* 370 */ + .quad sys_ni_syscall --- arch/arm/kernel/calls.S.~1~ Mon Dec 7 23:11:00 1998 +++ arch/arm/kernel/calls.S Mon Dec 7 23:11:05 1998 @@ -196,8 +196,9 @@ .long SYMBOL_NAME(sys_capget) /* 185 */ .long SYMBOL_NAME(sys_capset) .long SYMBOL_NAME(sys_sigaltstack_wrapper) + .long SYMBOL_NAME(sys_fsattr) - .rept NR_syscalls-186 + .rept NR_syscalls-187 .long SYMBOL_NAME(sys_ni_syscall) .endr #endif --- arch/i386/kernel/entry.S.~1~ Mon Dec 7 23:11:00 1998 +++ arch/i386/kernel/entry.S Mon Dec 7 23:11:05 1998 @@ -558,6 +558,7 @@ .long SYMBOL_NAME(sys_sendfile) .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ + .long SYMBOL_NAME(sys_fsattr) /* * NOTE!! This doesn' thave to be exact - we just have @@ -565,6 +566,6 @@ * entries. Don't panic if you notice that this hasn't * been shrunk every time we add a new system call. */ - .rept NR_syscalls-189 + .rept NR_syscalls-190 .long SYMBOL_NAME(sys_ni_syscall) .endr --- arch/m68k/kernel/entry.S.~1~ Mon Dec 7 23:11:00 1998 +++ arch/m68k/kernel/entry.S Mon Dec 7 23:11:05 1998 @@ -586,6 +586,7 @@ .long SYMBOL_NAME(sys_sendfile) .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ + .long SYMBOL_NAME(sys_fsattr) .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4 .long SYMBOL_NAME(sys_ni_syscall) --- arch/mips/kernel/syscalls.h.~1~ Mon Dec 7 23:11:00 1998 +++ arch/mips/kernel/syscalls.h Mon Dec 7 23:11:05 1998 @@ -225,3 +225,4 @@ SYS(sys_sendfile, 3) SYS(sys_ni_syscall, 0) SYS(sys_ni_syscall, 0) +SYS(sys_fsattr, 4) --- arch/ppc/kernel/misc.S.~1~ Mon Dec 7 23:11:00 1998 +++ arch/ppc/kernel/misc.S Mon Dec 7 23:11:05 1998 @@ -677,4 +677,5 @@ .long sys_sendfile .long sys_ni_syscall /* streams1 */ .long sys_ni_syscall /* streams2 */ - .space (NR_syscalls-183)*4 + .long sys_fsattr + .space (NR_syscalls-189)*4 --- arch/sparc/kernel/systbls.S.~1~ Mon Dec 7 23:11:00 1998 +++ arch/sparc/kernel/systbls.S Mon Dec 7 23:11:05 1998 @@ -68,7 +68,7 @@ /*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler /*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep /*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl -/*255*/ .long sys_aplib, sys_nis_syscall +/*255*/ .long sys_aplib, sys_fsattr, sys_nis_syscall /* Now the SunOS syscall table. */ --- arch/sparc64/kernel/systbls.S.~1~ Mon Dec 7 23:11:00 1998 +++ arch/sparc64/kernel/systbls.S Mon Dec 7 23:11:05 1998 @@ -127,7 +127,7 @@ /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep /*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl - .word sys_aplib + .word sys_aplib, sys_fsattr /* Now the 32-bit SunOS syscall table. */ --- fs/Makefile.~1~ Mon Aug 31 21:01:35 1998 +++ fs/Makefile Tue Dec 8 16:03:44 1998 @@ -13,7 +13,7 @@ O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \ super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \ - dcache.o inode.o attr.o bad_inode.o $(BINFMTS) + dcache.o inode.o attr.o bad_inode.o raw.o $(BINFMTS) MOD_LIST_NAME := FS_MODULES ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \ --- fs/block_dev.c.~1~ Mon Dec 7 23:11:00 1998 +++ fs/block_dev.c Wed Dec 9 17:15:53 1998 @@ -53,6 +53,11 @@ size = ((loff_t) blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS) >> blocksize_bits; else size = INT_MAX; + + if (filp->f_flags & O_DIRECT) + return rw_raw_io(WRITE, blocksize, 0, inode, + buf, count, ppos, size); + while (count>0) { if (block >= size) return written ? written : -ENOSPC; @@ -205,6 +210,10 @@ if (blocks == 0) return 0; } + + if (filp->f_flags & O_DIRECT) + return rw_raw_io(READ, blocksize, 0, inode, + buf, count, ppos, size); /* We do this in a two stage process. We first try to request as many blocks as we can, then we wait for the first one to --- fs/buffer.c.~1~ Mon Dec 7 23:11:00 1998 +++ fs/buffer.c Tue Dec 8 17:49:24 1998 @@ -891,7 +891,7 @@ bh->b_dev_id = dev_id; } -static void end_buffer_io_sync(struct buffer_head *bh, int uptodate) +void end_buffer_io_sync(struct buffer_head *bh, int uptodate) { mark_buffer_uptodate(bh, uptodate); unlock_buffer(bh); @@ -1048,8 +1048,10 @@ remove_from_hash_queue(buf); buf->b_dev = NODEV; refile_buffer(buf); - if (!--buf->b_count) + if (!--buf->b_count) { + try_to_free_buffer(buf, &buf, 6); return; + } printk("VFS: forgot an in-use buffer! (count=%d)\n", buf->b_count); } @@ -1192,7 +1194,7 @@ * no-buffer-head deadlock. Return NULL on failure; waiting for * buffer heads is now handled in create_buffers(). */ -static struct buffer_head * get_unused_buffer_head(int async) +struct buffer_head * get_unused_buffer_head(int async) { struct buffer_head * bh; @@ -1345,7 +1347,7 @@ * Free all temporary buffers belonging to a page. * This needs to be called with interrupts disabled. */ -static inline void free_async_buffers (struct buffer_head * bh) +void free_async_buffers (struct buffer_head * bh) { struct buffer_head *tmp, *tail; --- fs/ext2/inode.c.~1~ Mon Dec 7 23:11:00 1998 +++ fs/ext2/inode.c Mon Dec 7 23:11:05 1998 @@ -599,6 +672,10 @@ if (inode->u.ext2_i.i_flags & EXT2_NOATIME_FL) { inode->i_attr_flags |= ATTR_FLAG_NOATIME; inode->i_flags |= MS_NOATIME; + } + if (inode->u.ext2_i.i_flags & EXT2_DIRECT_FL) { + inode->i_attr_flags |= ATTR_FLAG_DIRECT; + inode->i_flags |= S_DIRECT; } return; --- fs/ext2/ioctl.c.~1~ Mon Dec 7 23:11:00 1998 +++ fs/ext2/ioctl.c Tue Dec 8 17:41:08 1998 @@ -16,6 +16,65 @@ #include #include +static int ext2_set_flags(struct inode *inode, unsigned int flags) +{ + flags = flags & EXT2_FL_USER_MODIFIABLE; + /* + * The IMMUTABLE and APPEND_ONLY flags can only be changed by + * the super user when the security level is zero. + */ + if ((flags & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) ^ + (inode->u.ext2_i.i_flags & + (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) { + /* This test looks nicer. Thanks to Pauline Middelink */ + if (!capable(CAP_LINUX_IMMUTABLE)) + return -EPERM; + } else + if ((current->fsuid != inode->i_uid) && + !capable(CAP_FOWNER)) + return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + inode->u.ext2_i.i_flags = (inode->u.ext2_i.i_flags & + ~EXT2_FL_USER_MODIFIABLE) | flags; + if (flags & EXT2_SYNC_FL) + inode->i_flags |= MS_SYNCHRONOUS; + else + inode->i_flags &= ~MS_SYNCHRONOUS; + if (flags & EXT2_APPEND_FL) + inode->i_flags |= S_APPEND; + else + inode->i_flags &= ~S_APPEND; + if (flags & EXT2_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + else + inode->i_flags &= ~S_IMMUTABLE; + if (flags & EXT2_NOATIME_FL) + inode->i_flags |= MS_NOATIME; + else + inode->i_flags &= ~MS_NOATIME; + if (flags & EXT2_DIRECT_FL) + inode->i_flags |= S_DIRECT; + else + inode->i_flags &= ~S_DIRECT; + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + return 0; +} + +static int ext2_set_version (struct inode *inode, unsigned long arg) +{ + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + if (get_user(inode->u.ext2_i.i_version, (int *) arg)) + return -EFAULT; + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + return 0; +} + int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) { @@ -30,57 +89,72 @@ case EXT2_IOC_SETFLAGS: if (get_user(flags, (int *) arg)) return -EFAULT; - flags = flags & EXT2_FL_USER_MODIFIABLE; - /* - * The IMMUTABLE and APPEND_ONLY flags can only be changed by - * the super user when the security level is zero. - */ - if ((flags & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) ^ - (inode->u.ext2_i.i_flags & - (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) { - /* This test looks nicer. Thanks to Pauline Middelink */ - if (!capable(CAP_LINUX_IMMUTABLE)) - return -EPERM; - } else - if ((current->fsuid != inode->i_uid) && - !capable(CAP_FOWNER)) - return -EPERM; - if (IS_RDONLY(inode)) - return -EROFS; - inode->u.ext2_i.i_flags = (inode->u.ext2_i.i_flags & - ~EXT2_FL_USER_MODIFIABLE) | flags; - if (flags & EXT2_SYNC_FL) - inode->i_flags |= MS_SYNCHRONOUS; - else - inode->i_flags &= ~MS_SYNCHRONOUS; - if (flags & EXT2_APPEND_FL) - inode->i_flags |= S_APPEND; - else - inode->i_flags &= ~S_APPEND; - if (flags & EXT2_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; - if (flags & EXT2_NOATIME_FL) - inode->i_flags |= MS_NOATIME; - else - inode->i_flags &= ~MS_NOATIME; - inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); - return 0; + return ext2_set_flags(inode, flags); case EXT2_IOC_GETVERSION: return put_user(inode->u.ext2_i.i_version, (int *) arg); case EXT2_IOC_SETVERSION: - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) - return -EPERM; - if (IS_RDONLY(inode)) - return -EROFS; - if (get_user(inode->u.ext2_i.i_version, (int *) arg)) - return -EFAULT; - inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); - return 0; + return ext2_set_version(inode, arg); default: return -ENOTTY; } } + +int ext2_fsattr (struct inode * inode, unsigned int len, int *in, int *out) +{ + int ret = 0; + + ext2_debug ("len = %d, arg = %p/%p\n", len, in, out); + + /* We have already checked that len >= 1 */ + if (in) { + int e2flags = 0; + if (in[0] & ATTR_FLAG_SYNCRONOUS) + e2flags |= EXT2_SYNC_FL; + if (in[0] & ATTR_FLAG_NOATIME) + e2flags |= EXT2_NOATIME_FL; + if (in[0] & ATTR_FLAG_APPEND) + e2flags |= EXT2_APPEND_FL; + if (in[0] & ATTR_FLAG_IMMUTABLE) + e2flags |= EXT2_IMMUTABLE_FL; + if (in[0] & ATTR_FLAG_NODIRATIME && S_ISDIR(inode->i_mode)) + e2flags |= EXT2_NOATIME_FL; + if (in[0] & ATTR_FLAG_DIRECT) + e2flags |= EXT2_DIRECT_FL; + if (in[0] & ATTR_FLAG_NODUMP) + e2flags |= EXT2_NODUMP_FL; + if (in[0] & ATTR_FLAG_COMPRESS) + e2flags |= EXT2_COMPR_FL; + if (in[0] & ATTR_FLAG_BTREE) + e2flags |= EXT2_BTREE_FL; + + ret = ext2_set_flags(inode, e2flags); + } + + if (out && !ret) { + int e2flags = inode->u.ext2_i.i_flags; + int attr = 0; + + if (e2flags & EXT2_SYNC_FL) + attr |= ATTR_FLAG_SYNCRONOUS; + if (e2flags & EXT2_NOATIME_FL) + attr |= ATTR_FLAG_NOATIME; + if (e2flags & EXT2_APPEND_FL) + attr |= ATTR_FLAG_APPEND; + if (e2flags & EXT2_IMMUTABLE_FL) + attr |= ATTR_FLAG_IMMUTABLE; + /* ext2fs has no internal NODIRATIME flag */ + if (e2flags & EXT2_DIRECT_FL) + attr |= ATTR_FLAG_DIRECT; + if (e2flags & EXT2_NODUMP_FL) + attr |= ATTR_FLAG_NODUMP; + if (e2flags & EXT2_COMPR_FL) + attr |= ATTR_FLAG_COMPRESS; + if (e2flags & EXT2_BTREE_FL) + attr |= ATTR_FLAG_BTREE; + + out[0] = attr; + } + + return ret; +} + --- fs/ext2/super.c.~1~ Mon Dec 7 23:11:00 1998 +++ fs/ext2/super.c Mon Dec 7 23:11:05 1998 @@ -138,7 +138,10 @@ ext2_put_super, ext2_write_super, ext2_statfs, - ext2_remount + ext2_remount, + NULL, /* clear_inode */ + NULL, /* umount_begin */ + ext2_fsattr, }; /* --- fs/ioctl.c.~1~ Mon Dec 7 23:11:01 1998 +++ fs/ioctl.c Mon Dec 7 23:11:05 1998 @@ -99,3 +99,73 @@ unlock_kernel(); return error; } + + +asmlinkage int sys_fsattr(const char * filename, unsigned int len, + const char *in, char *out) +{ + struct dentry * dentry; + struct inode * inode; + int error = 0; + char * tmp; + __u32 inbuf[MAXATTRLEN], outbuf[MAXATTRLEN]; + int i, ilen, ulen; + + /* The buffer length comes in as a byte count, but we'll be + * dealing with __u32[] internally. */ + if (len & (sizeof(__u32)-1)) { + error = -EINVAL; + goto out; + } + + /* How many attribute words do we know about? */ + ilen = len / sizeof(__u32); + if (ilen > MAXATTRLEN) + ilen = MAXATTRLEN; + if (!ilen) + goto out; + + for (i=0; id_inode; + if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->fsattr) + error = inode->i_sb->s_op->fsattr(inode, ilen, + in ? inbuf : 0, + out ? outbuf : 0); + dput(dentry); + + if (!error && out) + error = copy_to_user(out, outbuf, ulen); + +out_unlock: + unlock_kernel(); +out: + return error; +} + + --- fs/open.c.~1~ Mon Dec 7 23:11:01 1998 +++ fs/open.c Mon Dec 7 23:11:05 1998 @@ -656,6 +656,8 @@ goto cleanup_all; } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); + if (inode->i_flags & S_DIRECT) + f->f_flags |= O_DIRECT; return f; --- fs/raw.c.~1~ Tue Dec 8 00:28:40 1998 +++ fs/raw.c Wed Dec 9 20:22:13 1998 @@ -0,0 +1,323 @@ +/* + * linux/fs/raw.c Stephen C. Tweedie, 1998 + * + * Copyright (C) 1998, Red Hat Software + * + * This file may be redistributed under the terms of the GNU General + * Public License version 2 or later. + */ + +#include +#include +#include +#include + +#include +#include + +/* We split the raw IO into chunks of at most 64K to avoid reserving too + many resources for one single IO. */ +#define MAX_RAW_SECTORS 128 +#define MAX_RAW_PAGES (128 >> (PAGE_SHIFT - 9)) + +#if 0 +#define debugit(str, args...) printk(KERN_ERR "DEBUG, %s(%s:%d) " str "\n", __FUNCTION__, __FILE__, __LINE__ , ## args) +#else +#define debugit(x...) +#endif + +static struct page *get_page(unsigned long address) +{ + pgd_t *pgd; + pmd_t *pmd; + struct page *page; + unsigned long va; + + pgd = pgd_offset(current->mm, address); + pmd = pmd_alloc(pgd, address); + if (pmd) { + pte_t * pte = pte_alloc(pmd, address); + if (pte && pte_present(*pte)) { + va = pte_page(*pte); + page = &mem_map[MAP_NR(va)]; + debugit("Found user va %lx at kernel va %lx", + address, va); + return page; + } + } + + printk(KERN_ERR "Missing page in lock_down_page\n"); + return 0; +} + +static void release_pages(unsigned long ptr, unsigned long end) +{ + struct page *page; + for (; ptr < end; ptr += PAGE_SIZE) { + page = get_page(ptr); + if (page) { + clear_bit(PG_locked, &page->flags); + wake_up(&page->wait); + __free_page(page); + } + } +} + +static int lock_down_pages(int rw, struct page **page_array, + unsigned long start, unsigned long end) +{ + int repeat = 0, doublepage = 0; + int err; + unsigned long ptr; + struct vm_area_struct *vma; + struct page *page; + int i; + + err = verify_area((rw == READ) ? VERIFY_WRITE : VERIFY_READ, + (void *) start, end-start); + if (err) + goto out; + + repeat: + debugit("Getting semaphore"); + + down(¤t->mm->mmap_sem); + + /* + * First of all, try to fault in all of the necessary pages + */ + + vma = NULL; + err = -EFAULT; + + debugit("Faulting pages"); + + for (ptr = start; ptr < end; ptr += PAGE_SIZE) { + if (!vma || ptr >= vma->vm_end) { + vma = find_vma(current->mm, ptr); + if (!vma) + goto out_unlock; + } + if (!handle_mm_fault(current, vma, ptr, (rw==READ))) + goto out_unlock; + } + + /* + * Now, try to lock them. + */ + + debugit("Locking pages"); + + for (ptr = start, i = 0; ptr < end; ptr += PAGE_SIZE, i++) { + page = get_page(ptr); + if (!page) { + printk (KERN_ERR "Missing page in rw_raw_io\n"); + release_pages(start, ptr); + goto out_unlock; + } + if (PageLocked(page)) + goto retry; + atomic_inc(&page->count); + set_bit(PG_locked, &page->flags); + page_array[i] = page; + } + err = 0; + + out_unlock: + up(¤t->mm->mmap_sem); + out: + + debugit("Returning %d", err); + return err; + + retry: + /* + * Undo the locking so far, wait on the page we got to, and try again. + */ + release_pages(start, ptr); + up(¤t->mm->mmap_sem); + + /* + * Did we also unlock the page we got stuck on while we did this? + */ + if (!PageLocked(page)) { + /* If so, we may well have the page mapped twice in the + * IO address range. Bad news. Of course, it _might_ + * just be a coincidence, but if it happens more than + * once, chances are we have a double-mapped page. */ + if (++doublepage >= 3) { + err = -EINVAL; + goto out; + } + } + + /* + * Try again... + */ + wait_on_page(page); + if (++repeat < 16) + goto repeat; + err = -EAGAIN; + goto out; +} + +static int rw_raw_io_chunk (int rw, int size, + int (*bmap) (struct inode *, int), + struct inode * inode, const char * buf, + size_t count, loff_t offset, int max) +{ + struct page *page_array[MAX_RAW_PAGES]; + struct buffer_head *tmp, *bh[MAX_RAW_SECTORS]; + int bufs = 0; + int err = 0; + unsigned long start, userva, end; + int block = 0; + int page = 0, pages = 0, i, transferred; + char *data; + int blocksize_bits; + + /* Work out the start page for the user buffer, and the first + page beyond the end of it. */ + + start = ((unsigned long) buf) & PAGE_MASK; + end = ((unsigned long) buf + count + PAGE_SIZE - 1) & PAGE_MASK; + + err = lock_down_pages(rw, page_array, start, end); + if (err) + return err; + + i = size; + blocksize_bits = 0; + while(i != 1) { + blocksize_bits++; + i >>= 1; + } + + if (!bmap) + block = offset >> blocksize_bits; + + transferred = 0; + + /* Go through the chunk page by page, creating buffers for the + IO as we go. */ + for (userva = start; ; userva += PAGE_SIZE) { + + data = (char *) page_address(page_array[page]); + data += ((unsigned long) buf + transferred) & ~PAGE_MASK; + + for (; (unsigned long) buf < (userva + PAGE_SIZE); ) { + tmp = get_unused_buffer_head(0); + if (!tmp) { + err = -ENOMEM; + goto error; + } + + if (bmap) { + block = bmap(inode, offset); + if (!block) { + err = -EINVAL; + goto error; + } + } + + /* If we have an upper limit on the device size, + enforce that now. File overflow is always + indicated by a null block from bmap(), so we + don't care about that. */ + if (max && block >= max) + goto do_it; + + tmp->b_dev = B_FREE; + tmp->b_size = size; + tmp->b_data = data; + tmp->b_this_page = tmp; + + debugit ("Buffer %p(%s+%d) at %p", + tmp, kdevname(inode->i_rdev), block, data); + + init_buffer(tmp, inode->i_rdev, block, + end_buffer_io_sync, NULL); + if (rw == WRITE) { + set_bit(BH_Uptodate, &tmp->b_state); + set_bit(BH_Dirty, &tmp->b_state); + } + + bh[bufs++] = tmp; + buf += size; + transferred += size; + count -= size; + offset += size; + data += size; + block++; + + if (count <= 0) + goto do_it; + } + page++; + pages++; + } + + do_it: + debugit("Submitting %d ios...", bufs); + ll_rw_block(rw, bufs, bh); + + error: + for (i=bufs; --i >= 0; ) { + tmp = bh[i]; + debugit("Wait for buffer %p", tmp); + wait_on_buffer(tmp); + if (!err) { + if (rw == READ && !buffer_uptodate(tmp)) + err = -EIO; + } + free_async_buffers(tmp); + } + + debugit("Releasing pages"); + + release_pages(start, end); + if (err < 0) + return err; + return transferred; +} + +/* + * Perform raw IO. We assume we already have the kernel lock at this point. + */ + +int rw_raw_io (int rw, int size, int (*bmap) (struct inode *, int), + struct inode * inode, const char * buf, + size_t count, loff_t *ppos, int max) +{ + int chunk; + int retval; + int complete = 0; + loff_t offset = *ppos; + + /* + * Check that the buffer is blocksize-aligned, + * and that we are requesting a whole number of blocks. + */ + + if (((unsigned long) buf) & (size-1) || count & (size-1)) + return -EINVAL; + + while (count > 0) { + chunk = count; + if (chunk > (512 * MAX_RAW_SECTORS)) + chunk = (512 * MAX_RAW_SECTORS); + retval = rw_raw_io_chunk (rw, size, bmap, inode, + buf, chunk, offset, max); + if (retval < 0) + return retval; + complete += retval; + if (retval < chunk) + break; + count -= chunk; + buf += chunk; + offset += chunk; + } + *ppos += complete; + return complete; +} + --- include/asm-alpha/unistd.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-alpha/unistd.h Mon Dec 7 23:11:05 1998 @@ -307,6 +307,7 @@ #define __NR_getcwd 367 #define __NR_capget 368 #define __NR_capset 369 +#define __NR_fsattr 370 #if defined(__LIBRARY__) && defined(__GNUC__) --- include/asm-arm/fcntl.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-arm/fcntl.h Mon Dec 7 23:11:05 1998 @@ -18,6 +18,7 @@ #define FASYNC 020000 /* fcntl, for BSD compatibility */ #define O_DIRECTORY 040000 /* must be a directory */ #define O_NOFOLLOW 0100000 /* don't follow links */ +#define O_DIRECT 0200000 /* direct disk access hint */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get f_flags */ --- include/asm-arm/unistd.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-arm/unistd.h Mon Dec 7 23:11:05 1998 @@ -191,6 +191,10 @@ #define __NR_pwrite (__NR_SYSCALL_BASE+181) #define __NR_xstat (__NR_SYSCALL_BASE+182) #define __NR_xmknod (__NR_SYSCALL_BASE+183) +#define __NR_capget (__NR_SYSCALL_BASE+184) +#define __NR_capset (__NR_SYSCALL_BASE+185) +#define __NR_sigaltstack (__NR_SYSCALL_BASE+186) +#define __NR_fsattr (__NR_SYSCALL_BASE+187) #define __sys2(x) #x #define __sys1(x) __sys2(x) --- include/asm-i386/fcntl.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-i386/fcntl.h Mon Dec 7 23:11:05 1998 @@ -16,7 +16,7 @@ #define O_NDELAY O_NONBLOCK #define O_SYNC 010000 #define FASYNC 020000 /* fcntl, for BSD compatibility */ -#define O_DIRECT 040000 /* direct disk access hint - currently ignored */ +#define O_DIRECT 040000 /* direct disk access hint */ #define O_LARGEFILE 0100000 #define O_DIRECTORY 0200000 /* must be a directory */ #define O_NOFOLLOW 0400000 /* don't follow links */ --- include/asm-i386/unistd.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-i386/unistd.h Mon Dec 7 23:11:05 1998 @@ -194,6 +194,7 @@ #define __NR_sendfile 187 #define __NR_getpmsg 188 /* some people actually want streams */ #define __NR_putpmsg 189 /* some people actually want streams */ +#define __NR_fsattr 190 /* user-visible error numbers are in the range -1 - -122: see */ --- include/asm-m68k/fcntl.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-m68k/fcntl.h Mon Dec 7 23:11:05 1998 @@ -18,6 +18,7 @@ #define FASYNC 020000 /* fcntl, for BSD compatibility */ #define O_DIRECTORY 040000 /* must be a directory */ #define O_NOFOLLOW 0100000 /* don't follow links */ +#define O_DIRECT 0200000 /* direct disk access hint */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get f_flags */ --- include/asm-m68k/unistd.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-m68k/unistd.h Mon Dec 7 23:11:05 1998 @@ -193,6 +193,7 @@ #define __NR_sendfile 187 #define __NR_getpmsg 188 /* some people actually want streams */ #define __NR_putpmsg 189 /* some people actually want streams */ +#define __NR_fsattr 190 /* user-visible error numbers are in the range -1 - -122: see */ --- include/asm-mips/fcntl.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-mips/fcntl.h Mon Dec 7 23:11:05 1998 @@ -25,7 +25,7 @@ #define FASYNC 0x1000 /* fcntl, for BSD compatibility */ #define O_LARGEFILE 0x2000 /* allow large file opens - currently ignored */ #define O_NOFOLLOW 0x4000 /* Don't follow symbolic links */ -#define O_DIRECT 0x8000 /* direct disk access hint - currently ignored */ +#define O_DIRECT 0x8000 /* direct disk access hint */ #define O_DIRECTORY 0x10000 /* must be a directory */ #define O_NDELAY O_NONBLOCK --- include/asm-mips/unistd.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-mips/unistd.h Mon Dec 7 23:11:05 1998 @@ -1196,11 +1196,12 @@ #define __NR_sendfile (__NR_Linux + 207) #define __NR_getpmsg (__NR_Linux + 208) #define __NR_putpmsg (__NR_Linux + 209) +#define __NR_fsattr (__NR_Linux + 210) /* * Offset of the last Linux flavoured syscall */ -#define __NR_Linux_syscalls 209 +#define __NR_Linux_syscalls 210 #ifndef _LANGUAGE_ASSEMBLY --- include/asm-ppc/fcntl.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-ppc/fcntl.h Mon Dec 7 23:11:05 1998 @@ -17,6 +17,7 @@ #define O_SYNC 010000 #define FASYNC 020000 /* fcntl, for BSD compatibility */ #define O_DIRECTORY 040000 /* must be a directory */ +#define O_DIRECT 080000 /* direct disk access hint */ #define O_NOFOLLOW 0100000 /* don't follow links */ #define F_DUPFD 0 /* dup */ --- include/asm-ppc/unistd.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-ppc/unistd.h Mon Dec 7 23:11:05 1998 @@ -193,6 +193,7 @@ #define __NR_sendfile 186 #define __NR_getpmsg 187 /* some people actually want streams */ #define __NR_putpmsg 188 /* some people actually want streams */ +#define __NR_fsattr 189 #define __NR(n) #n --- include/asm-sparc/fcntl.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-sparc/fcntl.h Mon Dec 7 23:11:05 1998 @@ -19,6 +19,7 @@ #define O_NOCTTY 0x8000 /* not fcntl */ #define O_DIRECTORY 0x10000 /* must be a directory */ #define O_NOFOLLOW 0x20000 /* don't follow links */ +#define O_DIRECT 0x40000 /* raw, unbuffered access requested */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get f_flags */ --- include/asm-sparc/unistd.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-sparc/unistd.h Mon Dec 7 23:11:05 1998 @@ -271,6 +271,7 @@ #define __NR_fdatasync 253 #define __NR_nfsservctl 254 #define __NR_aplib 255 +#define __NR_fsattr 256 /* Linux Specific */ #define _syscall0(type,name) \ type name(void) \ --- include/asm-sparc64/fcntl.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-sparc64/fcntl.h Mon Dec 7 23:11:05 1998 @@ -19,6 +19,7 @@ #define O_NOCTTY 0x8000 /* not fcntl */ #define O_DIRECTORY 0x10000 /* must be a directory */ #define O_NOFOLLOW 0x20000 /* don't follow links */ +#define O_DIRECT 0x40000 /* direct disk access hint */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get f_flags */ --- include/asm-sparc64/unistd.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/asm-sparc64/unistd.h Mon Dec 7 23:11:05 1998 @@ -271,6 +271,7 @@ #define __NR_fdatasync 253 #define __NR_nfsservctl 254 #define __NR_aplib 255 +#define __NR_fsattr 256 /* Linux Specific */ #define _syscall0(type,name) \ type name(void) \ --- include/linux/ext2_fs.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/linux/ext2_fs.h Tue Dec 8 17:36:16 1998 @@ -198,10 +198,11 @@ #define EXT2_ECOMPR_FL 0x00000800 /* Compression error */ /* End compression flags --- maybe not all used */ #define EXT2_BTREE_FL 0x00001000 /* btree format dir */ +#define EXT2_DIRECT_FL 0x00002000 /* force unbuffered io */ #define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ -#define EXT2_FL_USER_VISIBLE 0x00001FFF /* User visible flags */ -#define EXT2_FL_USER_MODIFIABLE 0x000000FF /* User modifiable flags */ +#define EXT2_FL_USER_VISIBLE 0x00003FFF /* User visible flags */ +#define EXT2_FL_USER_MODIFIABLE 0x000020FF /* User modifiable flags */ /* * ioctl commands @@ -569,6 +570,7 @@ /* ioctl.c */ extern int ext2_ioctl (struct inode *, struct file *, unsigned int, unsigned long); +extern int ext2_fsattr (struct inode *, unsigned int, int *, int *); /* namei.c */ extern void ext2_release (struct inode *, struct file *); --- include/linux/fs.h.~1~ Mon Dec 7 23:11:01 1998 +++ include/linux/fs.h Wed Dec 9 17:17:20 1998 @@ -95,6 +95,7 @@ #define S_IMMUTABLE 512 /* Immutable file */ #define MS_NOATIME 1024 /* Do not update access times. */ #define MS_NODIRATIME 2048 /* Do not update directory access times */ +#define S_DIRECT 4096 /* Force raw (O_DIRECT) access */ /* * Flags that can be altered by MS_REMOUNT @@ -298,6 +299,12 @@ #define ATTR_FORCE 512 /* Not a change, but a change it */ #define ATTR_ATTR_FLAG 1024 +/* + * How many __u32s are required to encode the maximum legal attribute? + */ +#define MAXATTRLEN 1 + + /* * This is the Inode Attributes structure, used for notify_change(). It * uses the above definitions as flags, to know which values have changed. @@ -327,6 +334,10 @@ #define ATTR_FLAG_APPEND 4 /* Append-only file */ #define ATTR_FLAG_IMMUTABLE 8 /* Immutable file */ #define ATTR_FLAG_NODIRATIME 16 /* Don't update atime for directory */ +#define ATTR_FLAG_DIRECT 32 /* Force unbuffered IO */ +#define ATTR_FLAG_NODUMP 64 /* Do not dump(8) this file */ +#define ATTR_FLAG_COMPRESS 128 /* Try to compress this file */ +#define ATTR_FLAG_BTREE 256 /* Use btree format on dir */ /* * Includes for diskquotas and mount structures. @@ -438,6 +449,7 @@ #define FL_BROKEN 4 /* broken flock() emulation */ #define FL_ACCESS 8 /* for processes suspended by mandatory locking */ #define FL_LOCKD 16 /* lock held by rpc.lockd */ +#define FL_DIRECT 32 /* opened for raw (O_DIRECT) access */ /* * The POSIX file lock owner is determined by @@ -621,6 +633,7 @@ int (*remount_fs) (struct super_block *, int *, char *); void (*clear_inode) (struct inode *); void (*umount_begin) (struct super_block *); + int (*fsattr) (struct inode *, unsigned int, int *, int *); }; struct dquot_operations { @@ -832,8 +845,13 @@ extern struct buffer_head * bread(kdev_t dev, int block, int size); extern struct buffer_head * breada(kdev_t dev,int block, int size, unsigned int pos, unsigned int filesize); +extern void end_buffer_io_sync(struct buffer_head *bh, int uptodate); +extern struct buffer_head * get_unused_buffer_head(int async); +extern void free_async_buffers (struct buffer_head * bh); extern int brw_page(int, struct page *, kdev_t, int [], int, int); +extern int rw_raw_io (int, int, int (*bmap) (struct inode *, int), + struct inode *, const char *, size_t, loff_t *, int); extern int generic_readpage(struct file *, struct page *); extern int generic_file_mmap(struct file *, struct vm_area_struct *); --- include/linux/swap.h.~1~ Mon Dec 7 12:05:54 1998 +++ include/linux/swap.h Mon Dec 7 18:55:55 1998 @@ -90,6 +90,7 @@ extern struct page * read_swap_cache_async(unsigned long, int); #define read_swap_cache(entry) read_swap_cache_async(entry, 1); extern int FASTCALL(swap_count(unsigned long)); +extern struct page * lookup_swap_cache(unsigned long); /* * Make these inline later once they are working properly. */