summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
committer <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
commite7c2a72e2680827d6a733931273a93461c0d8d1b (patch)
treec9abeda78ef7504062bb2e816bcf3e3c9d680112 /fs
parentec6044459060a8c9ce7f64405c465d141898548c (diff)
Import of Linux/MIPS 1.3.0
Diffstat (limited to 'fs')
-rw-r--r--fs/Makefile60
-rw-r--r--fs/binfmt_elf.c126
-rw-r--r--fs/block_dev.c7
-rw-r--r--fs/buffer.c131
-rw-r--r--fs/dcache.c2
-rw-r--r--fs/devices.c8
-rw-r--r--fs/exec.c145
-rw-r--r--fs/ext/dir.c38
-rw-r--r--fs/ext/inode.c26
-rw-r--r--fs/ext/namei.c4
-rw-r--r--fs/ext2/CHANGES7
-rw-r--r--fs/ext2/acl.c15
-rw-r--r--fs/ext2/balloc.c19
-rw-r--r--fs/ext2/bitmap.c7
-rw-r--r--fs/ext2/dir.c54
-rw-r--r--fs/ext2/file.c35
-rw-r--r--fs/ext2/fsync.c19
-rw-r--r--fs/ext2/ialloc.c19
-rw-r--r--fs/ext2/inode.c32
-rw-r--r--fs/ext2/ioctl.c8
-rw-r--r--fs/ext2/namei.c7
-rw-r--r--fs/ext2/super.c87
-rw-r--r--fs/ext2/symlink.c7
-rw-r--r--fs/ext2/truncate.c55
-rw-r--r--fs/fcntl.c2
-rw-r--r--fs/fifo.c1
-rw-r--r--fs/hpfs/Makefile4
-rw-r--r--fs/hpfs/hpfs.h12
-rw-r--r--fs/hpfs/hpfs_caps.c170
-rw-r--r--fs/hpfs/hpfs_caps.h4
-rw-r--r--fs/hpfs/hpfs_fs.c156
-rw-r--r--fs/inode.c8
-rw-r--r--fs/ioctl.c5
-rw-r--r--fs/isofs/Makefile3
-rw-r--r--fs/isofs/dir.c331
-rw-r--r--fs/isofs/file.c4
-rw-r--r--fs/isofs/inode.c141
-rw-r--r--fs/isofs/namei.c15
-rw-r--r--fs/isofs/rock.c18
-rw-r--r--fs/isofs/symlink.c4
-rw-r--r--fs/isofs/util.c4
-rw-r--r--fs/locks.c779
-rw-r--r--fs/minix/Makefile2
-rw-r--r--fs/minix/bitmap.c8
-rw-r--r--fs/minix/dir.c47
-rw-r--r--fs/minix/file.c4
-rw-r--r--fs/minix/fsync.c4
-rw-r--r--fs/minix/inode.c63
-rw-r--r--fs/minix/namei.c9
-rw-r--r--fs/minix/symlink.c4
-rw-r--r--fs/minix/truncate.c4
-rw-r--r--fs/msdos/Makefile9
-rw-r--r--fs/msdos/buffer.c148
-rw-r--r--fs/msdos/dir.c58
-rw-r--r--fs/msdos/fat.c21
-rw-r--r--fs/msdos/file.c65
-rw-r--r--fs/msdos/inode.c196
-rw-r--r--fs/msdos/misc.c41
-rw-r--r--fs/msdos/mmap.c16
-rw-r--r--fs/msdos/msbuffer.h34
-rw-r--r--fs/msdos/namei.c16
-rw-r--r--fs/namei.c81
-rw-r--r--fs/nfs/Makefile2
-rw-r--r--fs/nfs/cache.c63
-rw-r--r--fs/nfs/dir.c41
-rw-r--r--fs/nfs/file.c6
-rw-r--r--fs/nfs/inode.c69
-rw-r--r--fs/nfs/mmap.c15
-rw-r--r--fs/nfs/proc.c6
-rw-r--r--fs/nfs/sock.c10
-rw-r--r--fs/nfs/symlink.c4
-rw-r--r--fs/open.c109
-rw-r--r--fs/pipe.c60
-rw-r--r--fs/proc/array.c436
-rw-r--r--fs/proc/base.c20
-rw-r--r--fs/proc/fd.c93
-rw-r--r--fs/proc/inode.c93
-rw-r--r--fs/proc/link.c7
-rw-r--r--fs/proc/mem.c241
-rw-r--r--fs/proc/net.c114
-rw-r--r--fs/proc/root.c74
-rw-r--r--fs/read_write.c32
-rw-r--r--fs/readdir.c145
-rw-r--r--fs/select.c62
-rw-r--r--fs/stat.c2
-rw-r--r--fs/super.c46
-rw-r--r--fs/sysv/Makefile3
-rw-r--r--fs/sysv/balloc.c4
-rw-r--r--fs/sysv/dir.c67
-rw-r--r--fs/sysv/file.c8
-rw-r--r--fs/sysv/fsync.c4
-rw-r--r--fs/sysv/ialloc.c4
-rw-r--r--fs/sysv/inode.c85
-rw-r--r--fs/sysv/namei.c5
-rw-r--r--fs/sysv/symlink.c4
-rw-r--r--fs/sysv/truncate.c4
-rw-r--r--fs/umsdos/Makefile7
-rw-r--r--fs/umsdos/README20
-rw-r--r--fs/umsdos/check.c31
-rw-r--r--fs/umsdos/dir.c18
-rw-r--r--fs/umsdos/emd.c4
-rw-r--r--fs/umsdos/file.c53
-rw-r--r--fs/umsdos/inode.c91
-rw-r--r--fs/umsdos/ioctl.c19
-rw-r--r--fs/umsdos/mangle.c14
-rw-r--r--fs/umsdos/namei.c269
-rw-r--r--fs/umsdos/rdir.c31
-rw-r--r--fs/umsdos/symlink.c3
-rw-r--r--fs/xiafs/Makefile3
-rw-r--r--fs/xiafs/bitmap.c6
-rw-r--r--fs/xiafs/dir.c39
-rw-r--r--fs/xiafs/file.c4
-rw-r--r--fs/xiafs/fsync.c4
-rw-r--r--fs/xiafs/inode.c66
-rw-r--r--fs/xiafs/namei.c8
-rw-r--r--fs/xiafs/symlink.c4
-rw-r--r--fs/xiafs/truncate.c4
117 files changed, 4004 insertions, 2041 deletions
diff --git a/fs/Makefile b/fs/Makefile
index 78dd720ce..7f2b18f5f 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -11,38 +11,58 @@ SUBDIRS = minix ext ext2 msdos proc isofs nfs xiafs umsdos hpfs sysv
ifdef CONFIG_MINIX_FS
FS_SUBDIRS := $(FS_SUBDIRS) minix
+else
+MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) minix
endif
+
ifdef CONFIG_EXT_FS
FS_SUBDIRS := $(FS_SUBDIRS) ext
endif
+
ifdef CONFIG_EXT2_FS
FS_SUBDIRS := $(FS_SUBDIRS) ext2
endif
+
ifdef CONFIG_MSDOS_FS
FS_SUBDIRS := $(FS_SUBDIRS) msdos
else
MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) msdos
endif
+
ifdef CONFIG_PROC_FS
FS_SUBDIRS := $(FS_SUBDIRS) proc
endif
+
ifdef CONFIG_ISO9660_FS
FS_SUBDIRS := $(FS_SUBDIRS) isofs
+else
+MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) isofs
endif
+
ifdef CONFIG_NFS_FS
FS_SUBDIRS := $(FS_SUBDIRS) nfs
+else
+MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) nfs
endif
+
ifdef CONFIG_XIA_FS
FS_SUBDIRS := $(FS_SUBDIRS) xiafs
+else
+MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) xiafs
endif
+
ifdef CONFIG_UMSDOS_FS
FS_SUBDIRS := $(FS_SUBDIRS) umsdos
else
MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) umsdos
endif
+
ifdef CONFIG_SYSV_FS
FS_SUBDIRS := $(FS_SUBDIRS) sysv
+else
+MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) sysv
endif
+
ifdef CONFIG_HPFS_FS
FS_SUBDIRS := $(FS_SUBDIRS) hpfs
endif
@@ -50,7 +70,7 @@ endif
ifdef CONFIG_BINFMT_ELF
BINFMTS := $(BINFMTS) binfmt_elf.o
else
-MODULES := $(MODULES) binfmt_elf.o
+MODULE_OBJS := $(MODULE_OBJS) binfmt_elf.o
endif
.c.s:
@@ -61,10 +81,10 @@ endif
$(AS) -o $*.o $<
OBJS= open.o read_write.o inode.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 \
+ 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 $(BINFMTS)
-all: fs.o filesystems.a modules modules_fs
+all: fs.o filesystems.a
fs.o: $(OBJS)
$(LD) -r -o fs.o $(OBJS)
@@ -75,36 +95,18 @@ filesystems.a: dummy
test ! -d $$i || \
{ $(MAKE) -C $$i; $(AR) rcs filesystems.a $$i/$$i.o; }; done
-ifdef MODULES
-
-modules:
- $(MAKE) CFLAGS="$(CFLAGS) -DMODULE" $(MODULES)
- (cd ../modules;for i in $(MODULES); do ln -sf ../fs/$$i .; done)
-
-else
-
-modules:
-
-endif
-
-ifdef MODULE_FS_SUBDIRS
-
-modules_fs:
- set -e; for i in $(MODULE_FS_SUBDIRS); do \
- test ! -d $$i || \
- { $(MAKE) -C $$i; }; done
-
-
-else
-
-modules_fs:
-
-endif
+modules: $(MODULE_OBJS)
+ for i in $(MODULE_FS_SUBDIRS); do $(MAKE) -C $$i modules; done
+ cd ../modules;for i in $(MODULE_OBJS); do ln -sf ../fs/$$i .; done
+ cd ../modules;for i in $(MODULE_FS_SUBDIRS); \
+ do echo $$i.o; ln -sf ../fs/$$i/$$i.o .; done > ../modules/FS_MODULES
depend dep:
$(CPP) -M *.c > .depend
- set -e; for i in $(SUBDIRS); do \
+ set -e; for i in $(FS_SUBDIRS); do \
test ! -d $$i || $(MAKE) -C $$i dep; done
+ set -e; for i in $(MODULE_FS_SUBDIRS); do \
+ test ! -d $$i || $(MAKE) -C $$i CFLAGS="$(CFLAGS) -DMODULE" dep; done
dummy:
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index fd5e41cdc..ecdffb85a 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -8,6 +8,15 @@
*
* Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
*/
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
@@ -24,16 +33,12 @@
#include <linux/personality.h>
#include <asm/segment.h>
+#include <asm/pgtable.h>
#include <linux/config.h>
-#ifndef CONFIG_BINFMT_ELF
-#include <linux/module.h>
-#include "../tools/version.h"
-#endif
-
#include <linux/unistd.h>
-typedef int (*sysfun_p)();
+typedef int (*sysfun_p)(int);
extern sysfun_p sys_call_table[];
#define SYS(name) (sys_call_table[__NR_##name])
@@ -45,7 +50,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
static int load_elf_library(int fd);
struct linux_binfmt elf_format = {
-#ifdef CONFIG_BINFMT_ELF
+#ifndef MODULE
NULL, NULL, load_elf_binary, load_elf_library, NULL
#else
NULL, &mod_use_count_, load_elf_binary, load_elf_library, NULL
@@ -58,19 +63,19 @@ struct linux_binfmt elf_format = {
be in memory */
-static void padzero(int elf_bss){
- unsigned int fpnt, nbyte;
+static void padzero(unsigned long elf_bss)
+{
+ unsigned long fpnt, nbyte;
- if(elf_bss & 0xfff) {
-
- nbyte = (PAGE_SIZE - (elf_bss & 0xfff)) & 0xfff;
- if(nbyte){
- verify_area(VERIFY_WRITE, (void *) elf_bss, nbyte);
-
- fpnt = elf_bss;
- while(fpnt & 0xfff) put_fs_byte(0, fpnt++);
- };
- };
+ nbyte = elf_bss & (PAGE_SIZE-1);
+ if (nbyte) {
+ nbyte = PAGE_SIZE - nbyte;
+ verify_area(VERIFY_WRITE, (void *) elf_bss, nbyte);
+ fpnt = elf_bss;
+ do {
+ put_fs_byte(0, fpnt++);
+ } while (--nbyte);
+ }
}
unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, int ibcs)
@@ -84,7 +89,7 @@ unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exe
mpnt->vm_task = current;
mpnt->vm_start = PAGE_MASK & (unsigned long) p;
mpnt->vm_end = TASK_SIZE;
- mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY;
+ mpnt->vm_page_prot = PAGE_COPY;
#ifdef VM_STACK_FLAGS
mpnt->vm_flags = VM_STACK_FLAGS;
mpnt->vm_pte = 0;
@@ -93,7 +98,6 @@ unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exe
mpnt->vm_flags = VM_GROWSDOWN;
# endif
#endif
- mpnt->vm_share = NULL;
mpnt->vm_inode = NULL;
mpnt->vm_offset = 0;
mpnt->vm_ops = NULL;
@@ -204,10 +208,13 @@ static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
eppnt = elf_phdata;
for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
if(eppnt->p_type == PT_LOAD) {
+ int elf_prot = (eppnt->p_flags & PF_R) ? PROT_READ : 0;
+ if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
+ if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
error = do_mmap(file,
eppnt->p_vaddr & 0xfffff000,
eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
- PROT_READ | PROT_WRITE | PROT_EXEC,
+ elf_prot,
MAP_PRIVATE | MAP_DENYWRITE | (interp_elf_ex->e_type == ET_EXEC ? MAP_FIXED : 0),
eppnt->p_offset & 0xfffff000);
@@ -315,9 +322,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
unsigned int elf_stack;
char passed_fileno[6];
-#ifndef CONFIG_BINFMT_ELF
MOD_INC_USE_COUNT;
-#endif
ibcs2_interpreter = 0;
status = 0;
@@ -326,9 +331,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (elf_ex.e_ident[0] != 0x7f ||
strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return -ENOEXEC;
}
@@ -338,9 +341,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
(elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
(!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
!bprm->inode->i_op->default_file_ops->mmap)){
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return -ENOEXEC;
};
@@ -356,9 +357,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
set_fs(old_fs);
if (retval < 0) {
kfree (elf_phdata);
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return retval;
}
@@ -371,9 +370,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if (elf_exec_fileno < 0) {
kfree (elf_phdata);
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return elf_exec_fileno;
}
@@ -420,9 +417,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if(retval < 0) {
kfree (elf_phdata);
kfree(elf_interpreter);
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return retval;
};
};
@@ -437,9 +432,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if(retval < 0) {
kfree(elf_interpreter);
kfree(elf_phdata);
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return -ELIBACC;
};
/* Now figure out which format our binary is */
@@ -456,9 +449,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
{
kfree(elf_interpreter);
kfree(elf_phdata);
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return -ELIBBAD;
};
}
@@ -483,9 +474,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
kfree(elf_interpreter);
}
kfree (elf_phdata);
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return -E2BIG;
}
}
@@ -502,7 +491,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
/* Do this so that we can load the interpreter, if need be. We will
change some of these later */
current->mm->rss = 0;
- bprm->p += change_ldt(0, bprm->page);
+ bprm->p += setup_arg_pages(0, bprm->page);
current->mm->start_stack = bprm->p;
/* Now we do a little grungy work by mmaping the ELF image into
@@ -537,20 +526,21 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
printk("Unable to load interpreter\n");
kfree(elf_phdata);
send_sig(SIGSEGV, current, 0);
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return 0;
};
};
if(elf_ppnt->p_type == PT_LOAD) {
+ int elf_prot = (elf_ppnt->p_flags & PF_R) ? PROT_READ : 0;
+ if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
+ if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
error = do_mmap(file,
elf_ppnt->p_vaddr & 0xfffff000,
elf_ppnt->p_filesz + (elf_ppnt->p_vaddr & 0xfff),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
+ elf_prot,
+ MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
elf_ppnt->p_offset & 0xfffff000);
#ifdef LOW_ELF_STACK
@@ -631,25 +621,20 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
printk("(brk) %x\n" , current->mm->brk);
#endif
- /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
- and some applications "depend" upon this behavior.
- Since we do not have the power to recompile these, we
- emulate the SVr4 behavior. Sigh. */
- error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, 0);
-
-#if defined (__i386__)
- regs->eip = elf_entry; /* eip, magic happens :-) */
- regs->esp = bprm->p; /* stack pointer */
-#elif defined (__mips__)
- regs->cp0_epc = elf_entry; /* eip, magic happens :-) */
- regs->reg29 = bprm->p; /* stack pointer */
-#endif
+ if( current->personality == PER_SVR4 )
+ {
+ /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
+ and some applications "depend" upon this behavior.
+ Since we do not have the power to recompile these, we
+ emulate the SVr4 behavior. Sigh. */
+ error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
+ MAP_FIXED | MAP_PRIVATE, 0);
+ }
+
+ start_thread(regs, elf_entry, bprm->p);
if (current->flags & PF_PTRACED)
send_sig(SIGTRAP, current, 0);
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return 0;
}
@@ -669,10 +654,7 @@ load_elf_library(int fd){
int error;
int i,j, k;
-#ifndef CONFIG_BINFMT_ELF
MOD_INC_USE_COUNT;
-#endif
-
len = 0;
file = current->files->fd[fd];
inode = file->f_inode;
@@ -681,18 +663,14 @@ load_elf_library(int fd){
set_fs(KERNEL_DS);
if (file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex)) != sizeof(elf_ex)) {
SYS(close)(fd);
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return -EACCES;
}
set_fs(USER_DS);
if (elf_ex.e_ident[0] != 0x7f ||
strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return -ENOEXEC;
}
@@ -700,18 +678,14 @@ load_elf_library(int fd){
if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
(elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
(!inode->i_op || !inode->i_op->default_file_ops->mmap)){
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return -ENOEXEC;
};
/* Now read in all of the header information */
if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) {
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return -ENOEXEC;
}
@@ -730,9 +704,7 @@ load_elf_library(int fd){
if(j != 1) {
kfree(elf_phdata);
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return -ENOEXEC;
};
@@ -752,9 +724,7 @@ load_elf_library(int fd){
SYS(close)(fd);
if (error != elf_phdata->p_vaddr & 0xfffff000) {
kfree(elf_phdata);
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return error;
}
@@ -767,13 +737,11 @@ load_elf_library(int fd){
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE, 0);
kfree(elf_phdata);
-#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
-#endif
return 0;
}
-#ifndef CONFIG_BINFMT_ELF
+#ifdef MODULE
char kernel_version[] = UTS_RELEASE;
int init_module(void) {
diff --git a/fs/block_dev.c b/fs/block_dev.c
index d19af6fa0..9d54d03c7 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -9,12 +9,15 @@
#include <linux/kernel.h>
#include <linux/locks.h>
#include <linux/fcntl.h>
+#include <linux/mm.h>
+
#include <asm/segment.h>
#include <asm/system.h>
extern int *blk_size[];
extern int *blksize_size[];
+#define MAX_BUF_PER_PAGE (PAGE_SIZE / 512)
#define NBUF 64
int block_write(struct inode * inode, struct file * filp, char * buf, int count)
@@ -24,7 +27,7 @@ int block_write(struct inode * inode, struct file * filp, char * buf, int count)
loff_t offset;
int chars;
int written = 0;
- int cluster_list[8];
+ int cluster_list[MAX_BUF_PER_PAGE];
struct buffer_head * bhlist[NBUF];
int blocks_per_cluster;
unsigned int size;
@@ -162,7 +165,7 @@ int block_read(struct inode * inode, struct file * filp, char * buf, int count)
int blocksize_bits, i;
unsigned int blocks, rblocks, left;
int bhrequest, uptodate;
- int cluster_list[8];
+ int cluster_list[MAX_BUF_PER_PAGE];
int blocks_per_cluster;
struct buffer_head ** bhb, ** bhe;
struct buffer_head * buflist[NBUF];
diff --git a/fs/buffer.c b/fs/buffer.c
index 9ee47cee6..c2d76a6db 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -16,7 +16,6 @@
* invalidate changed floppy-disk-caches.
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/major.h>
@@ -34,6 +33,7 @@ static char buffersize_index[9] = {-1, 0, 1, -1, 2, -1, -1, -1, 3};
static short int bufferindex_size[NR_SIZES] = {512, 1024, 2048, 4096};
#define BUFSIZE_INDEX(X) ((int) buffersize_index[(X)>>9])
+#define MAX_BUF_PER_PAGE (PAGE_SIZE / 512)
static int grow_buffers(int pri, int size);
static int shrink_specific_buffers(unsigned int priority, int size);
@@ -87,7 +87,7 @@ static union bdflush_param{
trim back the buffers */
} b_un;
unsigned int data[N_PARAM];
-} bdf_prm = {{25, 500, 64, 256, 15, 3000, 500, 1884, 2}};
+} bdf_prm = {{25, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}};
/* The lav constant is set for 1 minute, as long as the update process runs
every 5 seconds. If you change the frequency of update, the time
@@ -259,14 +259,16 @@ void invalidate_buffers(dev_t dev)
for(nlist = 0; nlist < NR_LIST; nlist++) {
bh = lru_list[nlist];
- for (i = nr_buffers_type[nlist]*2 ; --i > 0 ;
- bh = bh->b_next_free) {
+ for (i = nr_buffers_type[nlist]*2 ; --i > 0 ; bh = bh->b_next_free) {
if (bh->b_dev != dev)
- continue;
+ continue;
wait_on_buffer(bh);
- if (bh->b_dev == dev)
- bh->b_flushtime = bh->b_uptodate =
- bh->b_dirt = bh->b_req = 0;
+ if (bh->b_dev != dev)
+ continue;
+ if (bh->b_count)
+ continue;
+ bh->b_flushtime = bh->b_uptodate =
+ bh->b_dirt = bh->b_req = 0;
}
}
}
@@ -712,7 +714,7 @@ repeat:
bh = free_list[isize];
remove_from_free_list(bh);
-/* OK, FINALLY we know that this buffer is the only one of it's kind, */
+/* OK, FINALLY we know that this buffer is the only one of its kind, */
/* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */
bh->b_count=1;
bh->b_dirt=0;
@@ -742,20 +744,19 @@ void set_writetime(struct buffer_head * buf, int flag)
}
-static char buffer_disposition[] = {BUF_CLEAN, BUF_SHARED, BUF_LOCKED, BUF_SHARED,
- BUF_DIRTY, BUF_DIRTY, BUF_DIRTY, BUF_DIRTY};
-
void refile_buffer(struct buffer_head * buf){
- int i, dispose;
- i = 0;
+ int dispose;
if(buf->b_dev == 0xffff) panic("Attempt to refile free buffer\n");
- if(mem_map[MAP_NR((unsigned long) buf->b_data)] != 1) i = 1;
- if(buf->b_lock) i |= 2;
- if(buf->b_dirt) i |= 4;
- dispose = buffer_disposition[i];
- if(buf->b_list == BUF_SHARED && dispose == BUF_CLEAN)
- dispose = BUF_UNSHARED;
- if(dispose == -1) panic("Bad buffer settings (%d)\n", i);
+ if (buf->b_dirt)
+ dispose = BUF_DIRTY;
+ else if (mem_map[MAP_NR((unsigned long) buf->b_data)] > 1)
+ dispose = BUF_SHARED;
+ else if (buf->b_lock)
+ dispose = BUF_LOCKED;
+ else if (buf->b_list == BUF_SHARED)
+ dispose = BUF_UNSHARED;
+ else
+ dispose = BUF_CLEAN;
if(dispose == BUF_CLEAN) buf->b_lru_time = jiffies;
if(dispose != buf->b_list) {
if(dispose == BUF_DIRTY || dispose == BUF_UNSHARED)
@@ -964,7 +965,7 @@ static void read_buffers(struct buffer_head * bh[], int nrbuf)
{
int i;
int bhnum = 0;
- struct buffer_head * bhr[8];
+ struct buffer_head * bhr[MAX_BUF_PER_PAGE];
for (i = 0 ; i < nrbuf ; i++) {
if (bh[i] && !bh[i]->b_uptodate)
@@ -972,30 +973,44 @@ static void read_buffers(struct buffer_head * bh[], int nrbuf)
}
if (bhnum)
ll_rw_block(READ, bhnum, bhr);
- for (i = 0 ; i < nrbuf ; i++) {
+ for (i = nrbuf ; --i >= 0 ; ) {
if (bh[i]) {
wait_on_buffer(bh[i]);
}
}
}
+/*
+ * This actually gets enough info to try to align the stuff,
+ * but we don't bother yet.. We'll have to check that nobody
+ * else uses the buffers etc.
+ *
+ * "address" points to the new page we can use to move things
+ * around..
+ */
+static unsigned long try_to_align(struct buffer_head ** bh, int nrbuf,
+ unsigned long address)
+{
+ while (nrbuf-- > 0)
+ brelse(bh[nrbuf]);
+ return 0;
+}
+
static unsigned long check_aligned(struct buffer_head * first, unsigned long address,
dev_t dev, int *b, int size)
{
- struct buffer_head * bh[8];
+ struct buffer_head * bh[MAX_BUF_PER_PAGE];
unsigned long page;
unsigned long offset;
int block;
int nrbuf;
+ int aligned = 1;
- page = (unsigned long) first->b_data;
- if (page & ~PAGE_MASK) {
- brelse(first);
- return 0;
- }
- mem_map[MAP_NR(page)]++;
bh[0] = first;
nrbuf = 1;
+ page = (unsigned long) first->b_data;
+ if (page & ~PAGE_MASK)
+ aligned = 0;
for (offset = size ; offset < PAGE_SIZE ; offset += size) {
block = *++b;
if (!block)
@@ -1005,8 +1020,11 @@ static unsigned long check_aligned(struct buffer_head * first, unsigned long add
goto no_go;
bh[nrbuf++] = first;
if (page+offset != (unsigned long) first->b_data)
- goto no_go;
+ aligned = 0;
}
+ if (!aligned)
+ return try_to_align(bh, nrbuf, address);
+ mem_map[MAP_NR(page)]++;
read_buffers(bh,nrbuf); /* make sure they are actually read correctly */
while (nrbuf-- > 0)
brelse(bh[nrbuf]);
@@ -1016,14 +1034,13 @@ static unsigned long check_aligned(struct buffer_head * first, unsigned long add
no_go:
while (nrbuf-- > 0)
brelse(bh[nrbuf]);
- free_page(page);
return 0;
}
static unsigned long try_to_load_aligned(unsigned long address,
dev_t dev, int b[], int size)
{
- struct buffer_head * bh, * tmp, * arr[8];
+ struct buffer_head * bh, * tmp, * arr[MAX_BUF_PER_PAGE];
unsigned long offset;
int isize = BUFSIZE_INDEX(size);
int * p;
@@ -1114,7 +1131,7 @@ static inline unsigned long try_to_share_buffers(unsigned long address,
*/
unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, int no_share)
{
- struct buffer_head * bh[8];
+ struct buffer_head * bh[MAX_BUF_PER_PAGE];
unsigned long where;
int i, j;
@@ -1134,9 +1151,10 @@ unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, in
for (i=0, j=0; j<PAGE_SIZE ; i++, j += size, where += size) {
if (bh[i]) {
if (bh[i]->b_uptodate)
- memcpy((void *)where, bh[i]->b_data, size);
+ memcpy((void *) where, bh[i]->b_data, size);
brelse(bh[i]);
- }
+ } else
+ memset((void *) where, 0, size);
}
return address;
}
@@ -1196,6 +1214,9 @@ static int grow_buffers(int pri, int size)
return 1;
}
+
+/* =========== Reduce the buffer memory ============= */
+
/*
* try_to_free() checks if all the buffers on this particular page
* are unused, and free's the page if so.
@@ -1343,7 +1364,7 @@ static int shrink_specific_buffers(unsigned int priority, int size)
if(priority > 3 && nlist == BUF_SHARED) continue;
bh = lru_list[nlist];
if(!bh) continue;
- i = nr_buffers_type[nlist] >> priority;
+ i = 2*nr_buffers_type[nlist] >> priority;
for ( ; i-- > 0 ; bh = bh->b_next_free) {
/* We may have stalled while waiting for I/O to complete. */
if(bh->b_list != nlist) goto repeat1;
@@ -1371,6 +1392,8 @@ static int shrink_specific_buffers(unsigned int priority, int size)
}
+/* ================== Debugging =================== */
+
void show_buffers(void)
{
struct buffer_head * bh;
@@ -1410,6 +1433,9 @@ void show_buffers(void)
}
}
+
+/* ====================== Cluster patches for ext2 ==================== */
+
/*
* try_to_reassign() checks if all the buffers on this particular page
* are unused, and reassign to a new cluster them if this is true.
@@ -1435,7 +1461,7 @@ static inline int try_to_reassign(struct buffer_head * bh, struct buffer_head **
} while (tmp != bh);
tmp = bh;
- while((unsigned int) tmp->b_data & (PAGE_SIZE - 1))
+ while((unsigned long) tmp->b_data & (PAGE_SIZE - 1))
tmp = tmp->b_this_page;
/* This is the buffer at the head of the page */
@@ -1496,7 +1522,7 @@ static int reassign_cluster(dev_t dev,
*/
static unsigned long try_to_generate_cluster(dev_t dev, int block, int size)
{
- struct buffer_head * bh, * tmp, * arr[8];
+ struct buffer_head * bh, * tmp, * arr[MAX_BUF_PER_PAGE];
int isize = BUFSIZE_INDEX(size);
unsigned long offset;
unsigned long page;
@@ -1541,7 +1567,7 @@ static unsigned long try_to_generate_cluster(dev_t dev, int block, int size)
bh->b_this_page = tmp;
while (nblock-- > 0)
brelse(arr[nblock]);
- return 4;
+ return 4; /* ?? */
not_aligned:
while ((tmp = bh) != NULL) {
bh = bh->b_this_page;
@@ -1577,6 +1603,9 @@ unsigned long generate_cluster(dev_t dev, int b[], int size)
return reassign_cluster(dev, b[0], size);
}
+
+/* ===================== Init ======================= */
+
/*
* This initializes the initial buffer free list. nr_buffers_type is set
* to one less the actual number of buffers, as a sop to backwards
@@ -1587,23 +1616,25 @@ unsigned long generate_cluster(dev_t dev, int b[], int size)
void buffer_init(void)
{
int i;
- int isize = BUFSIZE_INDEX(BLOCK_SIZE);
+ int isize = BUFSIZE_INDEX(BLOCK_SIZE);
+ unsigned long total_memory;
- if (high_memory >= 4*1024*1024) {
- if(high_memory >= 16*1024*1024)
+ total_memory = MAP_NR(high_memory) << PAGE_SHIFT;
+ if (total_memory >= 4*1024*1024) {
+ if(total_memory >= 16*1024*1024)
nr_hash = 16381;
else
nr_hash = 4093;
} else {
nr_hash = 997;
- };
+ }
hash_table = (struct buffer_head **) vmalloc(nr_hash *
sizeof(struct buffer_head *));
-
buffer_pages = (struct buffer_head **) vmalloc(MAP_NR(high_memory) *
sizeof(struct buffer_head *));
+
for (i = 0 ; i < MAP_NR(high_memory) ; i++)
buffer_pages[i] = NULL;
@@ -1616,6 +1647,9 @@ void buffer_init(void)
return;
}
+
+/* ====================== bdflush support =================== */
+
/* This is a simple kernel daemon, whose job it is to provide a dynamically
* response to dirty buffers. Once this process is activated, we write back
* a limited number of buffers to the disks and then go back to sleep again.
@@ -1632,6 +1666,7 @@ static void wakeup_bdflush(int wait)
{
if(!bdflush_running){
printk("Warning - bdflush not running\n");
+cli();while(1);
sync_buffers(0,0);
return;
};
@@ -1724,7 +1759,7 @@ asmlinkage int sync_old_buffers(void)
* the tuning parameters. We would want to verify each parameter, however,
* to make sure that it is reasonable. */
-asmlinkage int sys_bdflush(int func, int data)
+asmlinkage int sys_bdflush(int func, long data)
{
int i, error;
int ndirty;
@@ -1747,7 +1782,7 @@ asmlinkage int sys_bdflush(int func, int data)
error = verify_area(VERIFY_WRITE, (void *) data, sizeof(int));
if (error)
return error;
- put_fs_long(bdf_prm.data[i], data);
+ put_user(bdf_prm.data[i], (int*)data);
return 0;
};
if (data < bdflush_min[i] || data > bdflush_max[i])
@@ -1818,7 +1853,7 @@ asmlinkage int sys_bdflush(int func, int data)
/* If there are still a lot of dirty buffers around, skip the sleep
and flush some more */
- if(nr_buffers_type[BUF_DIRTY] < (nr_buffers - nr_buffers_type[BUF_SHARED]) *
+ if(nr_buffers_type[BUF_DIRTY] <= (nr_buffers - nr_buffers_type[BUF_SHARED]) *
bdf_prm.b_un.nfract/100) {
if (current->signal & (1 << (SIGKILL-1))) {
bdflush_running--;
diff --git a/fs/dcache.c b/fs/dcache.c
index a40bdf316..b236a5cdb 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -29,7 +29,7 @@
* to be short.
*/
#define DCACHE_NAME_LEN 15
-#define DCACHE_SIZE 64
+#define DCACHE_SIZE 128
struct hash_list {
struct dir_cache_entry * next;
diff --git a/fs/devices.c b/fs/devices.c
index e79ea07d5..3eb269295 100644
--- a/fs/devices.c
+++ b/fs/devices.c
@@ -66,10 +66,6 @@ int register_chrdev(unsigned int major, const char * name, struct file_operation
{
if (major == 0) {
for (major = MAX_CHRDEV-1; major > 0; major--) {
- if (chrdevs[major].fops == fops)
- return major;
- }
- for (major = MAX_CHRDEV-1; major > 0; major--) {
if (chrdevs[major].fops == NULL) {
chrdevs[major].name = name;
chrdevs[major].fops = fops;
@@ -91,10 +87,6 @@ int register_blkdev(unsigned int major, const char * name, struct file_operation
{
if (major == 0) {
for (major = MAX_BLKDEV-1; major > 0; major--) {
- if (blkdevs[major].fops == fops)
- return major;
- }
- for (major = MAX_BLKDEV-1; major > 0; major--) {
if (blkdevs[major].fops == NULL) {
blkdevs[major].name = name;
blkdevs[major].fops = fops;
diff --git a/fs/exec.c b/fs/exec.c
index fe59a15ab..35ab4081d 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -42,6 +42,9 @@
#include <asm/system.h>
#include <asm/segment.h>
+#include <asm/pgtable.h>
+
+#include <linux/config.h>
asmlinkage int sys_exit(int exit_code);
asmlinkage int sys_brk(unsigned long);
@@ -50,6 +53,8 @@ static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
static int load_aout_library(int fd);
static int aout_core_dump(long signr, struct pt_regs * regs);
+extern void dump_thread(struct pt_regs *, struct user *);
+
/*
* Here are the actual binaries that will be accepted:
* add more with "register_binfmt()"..
@@ -106,14 +111,16 @@ int open_inode(struct inode * inode, int mode)
return -EINVAL;
f = get_empty_filp();
if (!f)
- return -EMFILE;
+ return -ENFILE;
fd = 0;
fpp = current->files->fd;
for (;;) {
if (!*fpp)
break;
- if (++fd > NR_OPEN)
- return -ENFILE;
+ if (++fd >= NR_OPEN) {
+ f->f_count--;
+ return -EMFILE;
+ }
fpp++;
}
*fpp = f;
@@ -164,8 +171,7 @@ static int aout_core_dump(long signr, struct pt_regs * regs)
unsigned short fs;
int has_dumped = 0;
char corefile[6+sizeof(current->comm)];
- int i;
- register int dump_start, dump_size;
+ unsigned long dump_start, dump_size;
struct user dump;
if (!current->dumpable)
@@ -206,55 +212,22 @@ static int aout_core_dump(long signr, struct pt_regs * regs)
if (!file.f_op->write)
goto close_coredump;
has_dumped = 1;
-/* changed the size calculations - should hopefully work better. lbt */
- dump.magic = CMAGIC;
- dump.start_code = 0;
-#if defined (__i386__)
- dump.start_stack = regs->esp & ~(PAGE_SIZE - 1);
-#elif defined (__mips__)
- dump.start_stack = regs->reg29 & ~(PAGE_SIZE - 1);
-#endif
- dump.u_tsize = ((unsigned long) current->mm->end_code) >> 12;
- dump.u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> 12;
- dump.u_dsize -= dump.u_tsize;
- dump.u_ssize = 0;
- for(i=0; i<8; i++) dump.u_debugreg[i] = current->debugreg[i];
- if (dump.start_stack < TASK_SIZE)
- dump.u_ssize = ((unsigned long) (TASK_SIZE - dump.start_stack)) >> 12;
+ strncpy(dump.u_comm, current->comm, sizeof(current->comm));
+ dump.u_ar0 = (struct pt_regs *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump)));
+ dump.signal = signr;
+ dump_thread(regs, &dump);
+
/* If the size of the dump file exceeds the rlimit, then see what would happen
if we wrote the stack, but not the data area. */
if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE >
current->rlim[RLIMIT_CORE].rlim_cur)
dump.u_dsize = 0;
+
/* Make sure we have enough room to write the stack and data areas. */
if ((dump.u_ssize+1) * PAGE_SIZE >
current->rlim[RLIMIT_CORE].rlim_cur)
dump.u_ssize = 0;
- strncpy(dump.u_comm, current->comm, sizeof(current->comm));
- dump.u_ar0 = (struct pt_regs *)(((int)(&dump.regs)) -((int)(&dump)));
- dump.signal = signr;
- dump.regs = *regs;
-#if defined (__i386__)
-/* Flag indicating the math stuff is valid. We don't support this for the
- soft-float routines yet */
- if (hard_math) {
- if ((dump.u_fpvalid = current->used_math) != 0) {
- if (last_task_used_math == current)
- __asm__("clts ; fnsave %0": :"m" (dump.i387));
- else
- memcpy(&dump.i387,&current->tss.i387.hard,sizeof(dump.i387));
- }
- } else {
- /* we should dump the emulator state here, but we need to
- convert it into standard 387 format first.. */
- dump.u_fpvalid = 0;
- }
-#elif defined (__mips__)
- /*
- * Dump the MIPS fpa.
- * FIXME: not implemented yet.
- */
-#endif
+
set_fs(KERNEL_DS);
/* struct user */
DUMP_WRITE(&dump,sizeof(dump));
@@ -335,9 +308,8 @@ unsigned long * create_tables(char * p,int argc,int envc,int ibcs)
mpnt->vm_task = current;
mpnt->vm_start = PAGE_MASK & (unsigned long) p;
mpnt->vm_end = TASK_SIZE;
- mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY;
+ mpnt->vm_page_prot = PAGE_COPY;
mpnt->vm_flags = VM_STACK_FLAGS;
- mpnt->vm_share = NULL;
mpnt->vm_ops = NULL;
mpnt->vm_offset = 0;
mpnt->vm_inode = NULL;
@@ -462,7 +434,7 @@ unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
return p;
}
-unsigned long change_ldt(unsigned long text_size,unsigned long * page)
+unsigned long setup_arg_pages(unsigned long text_size,unsigned long * page)
{
unsigned long code_limit,data_limit,code_base,data_base;
int i;
@@ -536,7 +508,6 @@ void flush_old_exec(struct linux_binprm * bprm)
int i;
int ch;
char * name;
- struct vm_area_struct * mpnt, *mpnt1;
current->dumpable = 1;
name = bprm->filename;
@@ -548,43 +519,14 @@ void flush_old_exec(struct linux_binprm * bprm)
current->comm[i++] = ch;
}
current->comm[i] = '\0';
- /* Release all of the old mmap stuff. */
- mpnt = current->mm->mmap;
- current->mm->mmap = NULL;
- while (mpnt) {
- mpnt1 = mpnt->vm_next;
- if (mpnt->vm_ops && mpnt->vm_ops->close)
- mpnt->vm_ops->close(mpnt);
- if (mpnt->vm_inode)
- iput(mpnt->vm_inode);
- kfree(mpnt);
- mpnt = mpnt1;
- }
-
-#if defined (__i386__)
- /* Flush the old ldt stuff... */
- if (current->ldt) {
- free_page((unsigned long) current->ldt);
- current->ldt = NULL;
- for (i=1 ; i<NR_TASKS ; i++) {
- if (task[i] == current) {
- set_ldt_desc(gdt+(i<<1)+
- FIRST_LDT_ENTRY,&default_ldt, 1);
- load_ldt(i);
- }
- }
- }
+ /* Release all of the old mmap stuff. */
+ exit_mmap(current);
- for (i=0 ; i<8 ; i++) current->debugreg[i] = 0;
-#elif defined (__mips__)
- /*
- * Do MIPS specific magic
- */
-#endif
+ flush_thread();
if (bprm->e_uid != current->euid || bprm->e_gid != current->egid ||
- !permission(bprm->inode,MAY_READ))
+ permission(bprm->inode,MAY_READ))
current->dumpable = 0;
current->signal = 0;
for (i=0 ; i<32 ; i++) {
@@ -615,10 +557,6 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
int retval;
int sh_bang = 0;
-#if defined (__i386__)
- if (regs->cs != USER_CS)
- return -EINVAL;
-#endif
bprm.p = PAGE_SIZE*MAX_ARG_PAGES-4;
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
bprm.page[i] = 0;
@@ -658,8 +596,9 @@ restart_interp:
bprm.e_uid = (i & S_ISUID) ? bprm.inode->i_uid : current->euid;
bprm.e_gid = (i & S_ISGID) ? bprm.inode->i_gid : current->egid;
}
- if (!permission(bprm.inode, MAY_EXEC) ||
- (!(bprm.inode->i_mode & 0111) && fsuser())) {
+ if ((retval = permission(bprm.inode, MAY_EXEC)) != 0)
+ goto exec_error2;
+ if (!(bprm.inode->i_mode & 0111) && fsuser()) {
retval = -EACCES;
goto exec_error2;
}
@@ -779,26 +718,6 @@ exec_error1:
return(retval);
}
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(struct pt_regs regs)
-{
- int error;
- char * filename;
-
-#if defined (__i386__)
- error = getname((char *) regs.ebx, &filename);
-#elif defined (__mips__)
- error = getname((char *) regs.reg3, &filename);
-#endif
- if (error)
- return error;
- error = do_execve(filename, (char **) regs.reg4, (char **) regs.reg5, &regs);
- putname(filename);
- return error;
-}
-
static void set_brk(unsigned long start, unsigned long end)
{
start = PAGE_ALIGN(start);
@@ -915,19 +834,13 @@ beyond_if:
set_brk(current->mm->start_brk, current->mm->brk);
- p += change_ldt(ex.a_text,bprm->page);
+ p += setup_arg_pages(ex.a_text,bprm->page);
p -= MAX_ARG_PAGES*PAGE_SIZE;
p = (unsigned long)create_tables((char *)p,
bprm->argc, bprm->envc,
current->personality != PER_LINUX);
current->mm->start_stack = p;
-#if defined (__i386__)
- regs->eip = ex.a_entry; /* eip, magic happens :-) */
- regs->esp = p; /* stack pointer */
-#elif defined (__mips__)
- regs->cp0_epc = ex.a_entry; /* eip, magic happens :-) */
- regs->reg29 = p; /* stack pointer */
-#endif
+ start_thread(regs, ex.a_entry, p);
if (current->flags & PF_PTRACED)
send_sig(SIGTRAP, current, 0);
return 0;
diff --git a/fs/ext/dir.c b/fs/ext/dir.c
index 10e30fafa..f4ae51d91 100644
--- a/fs/ext/dir.c
+++ b/fs/ext/dir.c
@@ -20,15 +20,12 @@
#include <linux/ext_fs.h>
#include <linux/stat.h>
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+3) & ~3)
-
static int ext_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
{
return -EISDIR;
}
-static int ext_readdir(struct inode *, struct file *, struct dirent *, int);
+static int ext_readdir(struct inode *, struct file *, void *, filldir_t);
static struct file_operations ext_dir_operations = {
NULL, /* lseek - default */
@@ -65,12 +62,11 @@ struct inode_operations ext_dir_inode_operations = {
};
static int ext_readdir(struct inode * inode, struct file * filp,
- struct dirent * dirent, int count)
+ void * dirent, filldir_t filldir)
{
+ int error;
unsigned int i;
- unsigned int ret;
off_t offset;
- char c;
struct buffer_head * bh;
struct ext_dir_entry * de;
@@ -78,8 +74,8 @@ static int ext_readdir(struct inode * inode, struct file * filp,
return -EBADF;
if ((filp->f_pos & 7) != 0)
return -EBADF;
- ret = 0;
- while (!ret && filp->f_pos < inode->i_size) {
+ error = 0;
+ while (!error && filp->f_pos < inode->i_size) {
offset = filp->f_pos & 1023;
bh = ext_bread(inode,(filp->f_pos)>>BLOCK_SIZE_BITS,0);
if (!bh) {
@@ -94,7 +90,7 @@ static int ext_readdir(struct inode * inode, struct file * filp,
}
offset = i;
de = (struct ext_dir_entry *) (offset + bh->b_data);
- while (!ret && offset < 1024 && filp->f_pos < inode->i_size) {
+ while (offset < 1024 && filp->f_pos < inode->i_size) {
if (de->rec_len < 8 || de->rec_len % 8 != 0 ||
de->rec_len < de->name_len + 8 ||
(de->rec_len + (off_t) filp->f_pos - 1) / 1024 > ((off_t) filp->f_pos / 1024)) {
@@ -106,26 +102,16 @@ static int ext_readdir(struct inode * inode, struct file * filp,
filp->f_pos = inode->i_size;
continue;
}
- offset += de->rec_len;
- filp->f_pos += de->rec_len;
if (de->inode) {
- for (i = 0; i < de->name_len; i++)
- if ((c = de->name[i]) != 0)
- put_fs_byte(c,i+dirent->d_name);
- else
- break;
- if (i) {
- put_fs_long(de->inode,&dirent->d_ino);
- put_fs_byte(0,i+dirent->d_name);
- put_fs_word(i,&dirent->d_reclen);
- ret = ROUND_UP(NAME_OFFSET(dirent)+i+1);
+ error = filldir(dirent, de->name, de->name_len, filp->f_pos, de->inode);
+ if (error)
break;
- }
}
- de = (struct ext_dir_entry *) ((char *) de
- + de->rec_len);
+ offset += de->rec_len;
+ filp->f_pos += de->rec_len;
+ ((char *) de) += de->rec_len;
}
brelse(bh);
}
- return ret;
+ return 0;
}
diff --git a/fs/ext/inode.c b/fs/ext/inode.c
index b3ca2e2cf..5601becb7 100644
--- a/fs/ext/inode.c
+++ b/fs/ext/inode.c
@@ -144,21 +144,19 @@ void ext_write_super (struct super_block *sb)
sb->s_dirt = 0;
}
-void ext_statfs (struct super_block *sb, struct statfs *buf)
+void ext_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
{
- long tmp;
-
- put_fs_long(EXT_SUPER_MAGIC, &buf->f_type);
- put_fs_long(1024, &buf->f_bsize);
- put_fs_long(sb->u.ext_sb.s_nzones << sb->u.ext_sb.s_log_zone_size,
- &buf->f_blocks);
- tmp = ext_count_free_blocks(sb);
- put_fs_long(tmp, &buf->f_bfree);
- put_fs_long(tmp, &buf->f_bavail);
- put_fs_long(sb->u.ext_sb.s_ninodes, &buf->f_files);
- put_fs_long(ext_count_free_inodes(sb), &buf->f_ffree);
- put_fs_long(EXT_NAME_LEN, &buf->f_namelen);
- /* Don't know what value to put in buf->f_fsid */
+ struct statfs tmp;
+
+ tmp.f_type = EXT_SUPER_MAGIC;
+ tmp.f_bsize = 1024;
+ tmp.f_blocks = sb->u.ext_sb.s_nzones << sb->u.ext_sb.s_log_zone_size;
+ tmp.f_bfree = ext_count_free_blocks(sb);
+ tmp.f_bavail = tmp.f_bfree;
+ tmp.f_files = sb->u.ext_sb.s_ninodes;
+ tmp.f_ffree = ext_count_free_inodes(sb);
+ tmp.f_namelen = EXT_NAME_LEN;
+ memcpy_tofs(buf, &tmp, bufsiz);
}
#define inode_bmap(inode,nr) ((inode)->u.ext_i.i_data[(nr)])
diff --git a/fs/ext/namei.c b/fs/ext/namei.c
index 85a411e94..f9e4b8499 100644
--- a/fs/ext/namei.c
+++ b/fs/ext/namei.c
@@ -285,6 +285,7 @@ printk ("ext_add_entry : creating next block\n");
de->rec_len = rec_len;
}
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->i_dirt = 1;
de->name_len = namelen;
for (i=0; i < namelen ; i++)
de->name[i] = name[i];
@@ -810,8 +811,7 @@ start_up:
retval = -EEXIST;
if (new_bh)
goto end_rename;
- retval = -EACCES;
- if (!permission(old_inode, MAY_WRITE))
+ if ((retval = permission(old_inode, MAY_WRITE)) != 0)
goto end_rename;
retval = -EINVAL;
if (subdir(new_dir, old_inode))
diff --git a/fs/ext2/CHANGES b/fs/ext2/CHANGES
index b760d18c7..a2495a41e 100644
--- a/fs/ext2/CHANGES
+++ b/fs/ext2/CHANGES
@@ -1,5 +1,12 @@
Changes from version 0.5 to version 0.5a
========================================
+ - Zero the partial block following the end of the file when a file
+ is truncated.
+ - Dates updated in the copyright.
+ - More checks when the filesystem is mounted: the count of blocks,
+ fragments, and inodes per group is checked against the block size.
+ - The buffers used by the error routines are now static variables, to
+ avoid using space on the kernel stack, as requested by Linus.
- Some cleanups in the error messages (some versions of syslog contain
a bug which truncates an error message if it contains '\n').
- Check that no data can be written to a file past the 2GB limit.
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index 91ef7c8cc..0b2701fe6 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -1,9 +1,10 @@
/*
* linux/fs/ext2/acl.c
*
- * Copyright (C) 1993, 1994 Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
+ * Copyright (C) 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
*/
/*
@@ -30,12 +31,12 @@ int ext2_permission (struct inode * inode, int mask)
* Nobody gets write access to an immutable file
*/
if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
- return 0;
+ return -EACCES;
/*
* Special case, access is always granted for root
*/
if (fsuser())
- return 1;
+ return 0;
/*
* If no ACL, checks using the file mode
*/
@@ -44,7 +45,7 @@ int ext2_permission (struct inode * inode, int mask)
else if (in_group_p (inode->i_gid))
mode >>= 3;
if (((mode & mask & S_IRWXO) == mask))
- return 1;
- else
return 0;
+ else
+ return -EACCES;
}
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index bc6faa7ed..c476fa2b2 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -1,9 +1,10 @@
/*
* linux/fs/ext2/balloc.c
*
- * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
*
* Enhanced block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
*/
@@ -75,7 +76,7 @@ static void read_block_bitmap (struct super_block * sb,
ext2_panic (sb, "read_block_bitmap",
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %lu",
- block_group, gdp->bg_block_bitmap);
+ block_group, (unsigned long) gdp->bg_block_bitmap);
sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group;
sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh;
}
@@ -232,7 +233,7 @@ void ext2_free_blocks (struct super_block * sb, unsigned long block,
mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
mark_buffer_dirty(bh, 1);
- if (sb->s_flags & MS_SYNC) {
+ if (sb->s_flags & MS_SYNCHRONOUS) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
@@ -249,8 +250,8 @@ void ext2_free_blocks (struct super_block * sb, unsigned long block,
* bitmap, and then for any free bit if that fails.
*/
int ext2_new_block (struct super_block * sb, unsigned long goal,
- unsigned long * prealloc_count,
- unsigned long * prealloc_block)
+ u32 * prealloc_count,
+ u32 * prealloc_block)
{
struct buffer_head * bh;
struct buffer_head * bh2;
@@ -441,7 +442,7 @@ got_block:
j = tmp;
mark_buffer_dirty(bh, 1);
- if (sb->s_flags & MS_SYNC) {
+ if (sb->s_flags & MS_SYNCHRONOUS) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
@@ -577,6 +578,6 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
ext2_error (sb, "ext2_check_blocks_bitmap",
"Wrong free blocks count in super block, "
"stored = %lu, counted = %lu",
- es->s_free_blocks_count, bitmap_count);
+ (unsigned long) es->s_free_blocks_count, bitmap_count);
unlock_super (sb);
}
diff --git a/fs/ext2/bitmap.c b/fs/ext2/bitmap.c
index 1084da16d..8b9b5d233 100644
--- a/fs/ext2/bitmap.c
+++ b/fs/ext2/bitmap.c
@@ -1,9 +1,10 @@
/*
* linux/fs/ext2/bitmap.c
*
- * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
*/
#include <linux/fs.h>
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index c98139bc6..5b8bf9cc7 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -1,9 +1,10 @@
/*
* linux/fs/ext2/dir.c
*
- * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
*
* from
*
@@ -22,16 +23,13 @@
#include <linux/sched.h>
#include <linux/stat.h>
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+3) & ~3)
-
static int ext2_dir_read (struct inode * inode, struct file * filp,
char * buf, int count)
{
return -EISDIR;
}
-static int ext2_readdir (struct inode *, struct file *, struct dirent *, int);
+static int ext2_readdir (struct inode *, struct file *, void *, filldir_t);
static struct file_operations ext2_dir_operations = {
NULL, /* lseek - default */
@@ -92,16 +90,17 @@ int ext2_check_dir_entry (char * function, struct inode * dir,
if (error_msg != NULL)
ext2_error (dir->i_sb, function, "bad directory entry: %s\n"
"offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
- error_msg, offset, de->inode, de->rec_len,
+ error_msg, offset, (unsigned long) de->inode, de->rec_len,
de->name_len);
return error_msg == NULL ? 1 : 0;
}
static int ext2_readdir (struct inode * inode, struct file * filp,
- struct dirent * dirent, int count)
+ void * dirent, filldir_t filldir)
{
+ int error = 0;
unsigned long offset, blk;
- int i, num, stored, dlen;
+ int i, num, stored;
struct buffer_head * bh, * tmp, * bha[16];
struct ext2_dir_entry * de;
struct super_block * sb;
@@ -115,7 +114,7 @@ static int ext2_readdir (struct inode * inode, struct file * filp,
bh = NULL;
offset = filp->f_pos & (sb->s_blocksize - 1);
- while (count > 0 && !stored && filp->f_pos < inode->i_size) {
+ while (!error && !stored && filp->f_pos < inode->i_size) {
blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb);
bh = ext2_bread (inode, blk, 0, &err);
if (!bh) {
@@ -167,7 +166,7 @@ revalidate:
filp->f_version = inode->i_version;
}
- while (count > 0 && filp->f_pos < inode->i_size
+ while (!error && filp->f_pos < inode->i_size
&& offset < sb->s_blocksize) {
de = (struct ext2_dir_entry *) (bh->b_data + offset);
if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
@@ -179,18 +178,8 @@ revalidate:
brelse (bh);
return stored;
}
+ offset += de->rec_len;
if (de->inode) {
- dlen = ROUND_UP(NAME_OFFSET(dirent)
- + de->name_len + 1);
- /* Old libc libraries always use a
- count of 1. */
- if (count == 1 && !stored)
- count = dlen;
- if (count < dlen) {
- count = 0;
- break;
- }
-
/* We might block in the next section
* if the data destination is
* currently swapped out. So, use a
@@ -198,22 +187,13 @@ revalidate:
* not the directory has been modified
* during the copy operation. */
version = inode->i_version;
- i = de->name_len;
- memcpy_tofs (dirent->d_name, de->name, i);
- put_fs_long (de->inode, &dirent->d_ino);
- put_fs_byte (0, dirent->d_name + i);
- put_fs_word (i, &dirent->d_reclen);
- put_fs_long (dlen, &dirent->d_off);
+ error = filldir(dirent, de->name, de->name_len, filp->f_pos, de->inode);
+ if (error)
+ break;
if (version != inode->i_version)
goto revalidate;
- dcache_add(inode, de->name, de->name_len,
- de->inode);
-
- stored += dlen;
- count -= dlen;
- ((char *) dirent) += dlen;
+ stored ++;
}
- offset += de->rec_len;
filp->f_pos += de->rec_len;
}
offset = 0;
@@ -223,5 +203,5 @@ revalidate:
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
- return stored;
+ return 0;
}
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 20628b349..9491942c5 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -1,9 +1,10 @@
/*
* linux/fs/ext2/file.c
*
- * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
*
* from
*
@@ -195,9 +196,37 @@ static int ext2_file_read (struct inode * inode, struct file * filp,
left -= chars;
read += chars;
if (*bhe) {
+#if 0
+printk("ext2_file_read() #1:\n");
+printk("ext2_file_read() #1.1: ");print_sp();
+#endif
memcpy_tofs (buf, offset + (*bhe)->b_data,
chars);
+#if 0
+printk("ext2_file_read() #2: buf == %08x\n", offset+(*bhe)->b_data);
+if(!buf)
+ {
+#if 0
+ printk("Flushing caches...\n");
+ sys_cacheflush(0, ~0, 3);
+#endif
+ printk("dumping #1 at %08lx...\n", (unsigned long) buf);
+ dump16(buf);
+ printk("dumping #2 at %08lx...\n", (unsigned long) (offset+(*bhe)->b_data));
+ dump16(offset+(*bhe)->b_data);
+#if 0
+ printk("Jumping to 0x0\n");
+ __asm__ __volatile__ ("jr\t%0;nop"::"r" (0));
+ printk("Freezing ...\n");
+ while(1);
+#endif
+ }
+/*dump_list(0);*/
+#endif
brelse (*bhe);
+#if 0
+printk("ext2_file_read() #3:\n");
+#endif
buf += chars;
} else {
while (chars-- > 0)
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index 2f79c4749..dd3d992c3 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -27,7 +27,7 @@
#define blocksize (EXT2_BLOCK_SIZE(inode->i_sb))
#define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb))
-static int sync_block (struct inode * inode, unsigned long * block, int wait)
+static int sync_block (struct inode * inode, u32 * block, int wait)
{
struct buffer_head * bh;
int tmp;
@@ -55,7 +55,7 @@ static int sync_block (struct inode * inode, unsigned long * block, int wait)
return 0;
}
-static int sync_iblock (struct inode * inode, unsigned long * iblock,
+static int sync_iblock (struct inode * inode, u32 * iblock,
struct buffer_head ** bh, int wait)
{
int rc, tmp;
@@ -94,8 +94,7 @@ static int sync_direct (struct inode * inode, int wait)
return err;
}
-static int sync_indirect (struct inode * inode, unsigned long * iblock,
- int wait)
+static int sync_indirect (struct inode * inode, u32 * iblock, int wait)
{
int i;
struct buffer_head * ind_bh;
@@ -107,7 +106,7 @@ static int sync_indirect (struct inode * inode, unsigned long * iblock,
for (i = 0; i < addr_per_block; i++) {
rc = sync_block (inode,
- ((unsigned long *) ind_bh->b_data) + i,
+ ((u32 *) ind_bh->b_data) + i,
wait);
if (rc > 0)
break;
@@ -118,8 +117,7 @@ static int sync_indirect (struct inode * inode, unsigned long * iblock,
return err;
}
-static int sync_dindirect (struct inode * inode, unsigned long * diblock,
- int wait)
+static int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
{
int i;
struct buffer_head * dind_bh;
@@ -131,7 +129,7 @@ static int sync_dindirect (struct inode * inode, unsigned long * diblock,
for (i = 0; i < addr_per_block; i++) {
rc = sync_indirect (inode,
- ((unsigned long *) dind_bh->b_data) + i,
+ ((u32 *) dind_bh->b_data) + i,
wait);
if (rc > 0)
break;
@@ -142,8 +140,7 @@ static int sync_dindirect (struct inode * inode, unsigned long * diblock,
return err;
}
-static int sync_tindirect (struct inode * inode, unsigned long * tiblock,
- int wait)
+static int sync_tindirect (struct inode * inode, u32 * tiblock, int wait)
{
int i;
struct buffer_head * tind_bh;
@@ -155,7 +152,7 @@ static int sync_tindirect (struct inode * inode, unsigned long * tiblock,
for (i = 0; i < addr_per_block; i++) {
rc = sync_dindirect (inode,
- ((unsigned long *) tind_bh->b_data) + i,
+ ((u32 *) tind_bh->b_data) + i,
wait);
if (rc > 0)
break;
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 69c9e2224..9102d02b2 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -1,9 +1,10 @@
/*
* linux/fs/ext2/ialloc.c
*
- * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
*
* BSD ufs-inspired inode and directory allocation by
* Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
@@ -74,7 +75,7 @@ static void read_inode_bitmap (struct super_block * sb,
ext2_panic (sb, "read_inode_bitmap",
"Cannot read inode bitmap - "
"block_group = %lu, inode_bitmap = %lu",
- block_group, gdp->bg_inode_bitmap);
+ block_group, (unsigned long) gdp->bg_inode_bitmap);
sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group;
sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh;
}
@@ -247,7 +248,7 @@ void ext2_free_inode (struct inode * inode)
set_inode_dtime (inode, gdp);
}
mark_buffer_dirty(bh, 1);
- if (sb->s_flags & MS_SYNC) {
+ if (sb->s_flags & MS_SYNCHRONOUS) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
@@ -358,7 +359,7 @@ repeat:
else
{
/*
- * Try to place the inode in it's parent directory
+ * Try to place the inode in its parent directory
*/
i = dir->u.ext2_i.i_block_group;
tmp = get_group_desc (sb, i, &bh2);
@@ -414,7 +415,7 @@ repeat:
goto repeat;
}
mark_buffer_dirty(bh, 1);
- if (sb->s_flags & MS_SYNC) {
+ if (sb->s_flags & MS_SYNCHRONOUS) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
@@ -476,7 +477,7 @@ repeat:
inode->u.ext2_i.i_block_group = i;
inode->i_op = NULL;
if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
- inode->i_flags |= MS_SYNC;
+ inode->i_flags |= MS_SYNCHRONOUS;
insert_inode_hash(inode);
inc_inode_version (inode, gdp, mode);
@@ -549,6 +550,6 @@ void ext2_check_inodes_bitmap (struct super_block * sb)
ext2_error (sb, "ext2_check_inodes_bitmap",
"Wrong free inodes count in super block, "
"stored = %lu, counted = %lu",
- es->s_free_inodes_count, bitmap_count);
+ (unsigned long) es->s_free_inodes_count, bitmap_count);
unlock_super (sb);
}
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 7a3c37b79..127f4a9cd 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1,9 +1,10 @@
/*
* linux/fs/ext2/inode.c
*
- * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
*
* from
*
@@ -24,6 +25,7 @@
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/locks.h>
+#include <linux/mm.h>
void ext2_put_inode (struct inode * inode)
{
@@ -45,7 +47,7 @@ static int block_bmap (struct buffer_head * bh, int nr)
if (!bh)
return 0;
- tmp = ((unsigned long *) bh->b_data)[nr];
+ tmp = ((u32 *) bh->b_data)[nr];
brelse (bh);
return tmp;
}
@@ -99,7 +101,7 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal)
"cannot get block %lu", result);
return 0;
}
- memset (bh->b_data, 0, inode->i_sb->s_blocksize);
+ memset(bh->b_data, 0, inode->i_sb->s_blocksize);
bh->b_uptodate = 1;
mark_buffer_dirty(bh, 1);
brelse (bh);
@@ -181,8 +183,8 @@ int ext2_bmap (struct inode * inode, int block)
static struct buffer_head * inode_getblk (struct inode * inode, int nr,
int create, int new_block, int * err)
{
+ u32 * p;
int tmp, goal = 0;
- unsigned long * p;
struct buffer_head * result;
int blocks = inode->i_sb->s_blocksize / 512;
@@ -249,7 +251,7 @@ static struct buffer_head * block_getblk (struct inode * inode,
int new_block, int * err)
{
int tmp, goal = 0;
- unsigned long * p;
+ u32 * p;
struct buffer_head * result;
int blocks = inode->i_sb->s_blocksize / 512;
@@ -263,7 +265,7 @@ static struct buffer_head * block_getblk (struct inode * inode,
return NULL;
}
}
- p = (unsigned long *) bh->b_data + nr;
+ p = (u32 *) bh->b_data + nr;
repeat:
tmp = *p;
if (tmp) {
@@ -286,8 +288,8 @@ repeat:
goal = inode->u.ext2_i.i_next_alloc_goal;
if (!goal) {
for (tmp = nr - 1; tmp >= 0; tmp--) {
- if (((unsigned long *) bh->b_data)[tmp]) {
- goal = ((unsigned long *)bh->b_data)[tmp];
+ if (((u32 *) bh->b_data)[tmp]) {
+ goal = ((u32 *)bh->b_data)[tmp];
break;
}
}
@@ -324,7 +326,7 @@ static int block_getcluster (struct inode * inode, struct buffer_head * bh,
int nr,
int blocksize)
{
- unsigned long * p;
+ u32 * p;
int firstblock = 0;
int result = 0;
int i;
@@ -337,7 +339,7 @@ static int block_getcluster (struct inode * inode, struct buffer_head * bh,
if(nr + 3 > EXT2_ADDR_PER_BLOCK(inode->i_sb)) goto out;
for(i=0; i< (PAGE_SIZE / inode->i_sb->s_blocksize); i++) {
- p = (unsigned long *) bh->b_data + nr + i;
+ p = (u32 *) bh->b_data + nr + i;
/* All blocks in cluster must already be allocated */
if(*p == 0) goto out;
@@ -345,9 +347,9 @@ static int block_getcluster (struct inode * inode, struct buffer_head * bh,
/* See if aligned correctly */
if(i==0) firstblock = *p;
else if(*p != firstblock + i) goto out;
- };
+ }
- p = (unsigned long *) bh->b_data + nr;
+ p = (u32 *) bh->b_data + nr;
result = generate_cluster(bh->b_dev, (int *) p, blocksize);
out:
@@ -567,7 +569,7 @@ void ext2_read_inode (struct inode * inode)
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
- inode->i_flags |= MS_SYNC;
+ inode->i_flags |= MS_SYNCHRONOUS;
if (inode->u.ext2_i.i_flags & EXT2_APPEND_FL)
inode->i_flags |= S_APPEND;
if (inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL)
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index 447968ef0..e0de8de11 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -1,9 +1,10 @@
/*
* linux/fs/ext2/ioctl.c
*
- * Copyright (C) 1993, 1994 Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
+ * Copyright (C) 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
*/
#include <asm/segment.h>
@@ -13,6 +14,7 @@
#include <linux/ext2_fs.h>
#include <linux/ioctl.h>
#include <linux/sched.h>
+#include <linux/mm.h>
int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
unsigned long arg)
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index f56c5404e..6c0b277e2 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -1,9 +1,10 @@
/*
* linux/fs/ext2/namei.c
*
- * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
*
* from
*
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 37fae41ad..5cd418364 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -1,9 +1,10 @@
/*
* linux/fs/ext2/super.c
*
- * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
*
* from
*
@@ -26,10 +27,11 @@
#include <linux/string.h>
#include <linux/locks.h>
+static char error_buf[1024];
+
void ext2_error (struct super_block * sb, const char * function,
const char * fmt, ...)
{
- char buf[1024];
va_list args;
if (!(sb->s_flags & MS_RDONLY)) {
@@ -39,15 +41,15 @@ void ext2_error (struct super_block * sb, const char * function,
sb->s_dirt = 1;
}
va_start (args, fmt);
- vsprintf (buf, fmt, args);
+ vsprintf (error_buf, fmt, args);
va_end (args);
if (test_opt (sb, ERRORS_PANIC) ||
(sb->u.ext2_sb.s_es->s_errors == EXT2_ERRORS_PANIC &&
!test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_RO)))
panic ("EXT2-fs panic (device %d/%d): %s: %s\n",
- MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf);
+ MAJOR(sb->s_dev), MINOR(sb->s_dev), function, error_buf);
printk (KERN_CRIT "EXT2-fs error (device %d/%d): %s: %s\n",
- MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf);
+ MAJOR(sb->s_dev), MINOR(sb->s_dev), function, error_buf);
if (test_opt (sb, ERRORS_RO) ||
(sb->u.ext2_sb.s_es->s_errors == EXT2_ERRORS_RO &&
!test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_PANIC))) {
@@ -59,7 +61,6 @@ void ext2_error (struct super_block * sb, const char * function,
NORET_TYPE void ext2_panic (struct super_block * sb, const char * function,
const char * fmt, ...)
{
- char buf[1024];
va_list args;
if (!(sb->s_flags & MS_RDONLY)) {
@@ -69,23 +70,22 @@ NORET_TYPE void ext2_panic (struct super_block * sb, const char * function,
sb->s_dirt = 1;
}
va_start (args, fmt);
- vsprintf (buf, fmt, args);
+ vsprintf (error_buf, fmt, args);
va_end (args);
panic ("EXT2-fs panic (device %d/%d): %s: %s\n",
- MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf);
+ MAJOR(sb->s_dev), MINOR(sb->s_dev), function, error_buf);
}
void ext2_warning (struct super_block * sb, const char * function,
const char * fmt, ...)
{
- char buf[1024];
va_list args;
va_start (args, fmt);
- vsprintf (buf, fmt, args);
+ vsprintf (error_buf, fmt, args);
va_end (args);
printk (KERN_WARNING "EXT2-fs warning (device %d/%d): %s: %s\n",
- MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf);
+ MAJOR(sb->s_dev), MINOR(sb->s_dev), function, error_buf);
}
void ext2_put_super (struct super_block * sb)
@@ -360,7 +360,7 @@ static int ext2_check_descriptors (struct super_block * sb)
ext2_error (sb, "ext2_check_descriptors",
"Block bitmap for group %d"
" not in group (block %lu)!",
- i, gdp->bg_block_bitmap);
+ i, (unsigned long) gdp->bg_block_bitmap);
return 0;
}
if (gdp->bg_inode_bitmap < block ||
@@ -369,7 +369,7 @@ static int ext2_check_descriptors (struct super_block * sb)
ext2_error (sb, "ext2_check_descriptors",
"Inode bitmap for group %d"
" not in group (block %lu)!",
- i, gdp->bg_inode_bitmap);
+ i, (unsigned long) gdp->bg_inode_bitmap);
return 0;
}
if (gdp->bg_inode_table < block ||
@@ -379,7 +379,7 @@ static int ext2_check_descriptors (struct super_block * sb)
ext2_error (sb, "ext2_check_descriptors",
"Inode table for group %d"
" not in group (block %lu)!",
- i, gdp->bg_inode_table);
+ i, (unsigned long) gdp->bg_inode_table);
return 0;
}
block += EXT2_BLOCKS_PER_GROUP(sb);
@@ -553,6 +553,31 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
return NULL;
}
+ if (sb->u.ext2_sb.s_blocks_per_group > sb->s_blocksize * 8) {
+ sb->s_dev = 0;
+ unlock_super (sb);
+ brelse (bh);
+ printk ("EXT2-fs: #blocks per group too big: %lu\n",
+ sb->u.ext2_sb.s_blocks_per_group);
+ return NULL;
+ }
+ if (sb->u.ext2_sb.s_frags_per_group > sb->s_blocksize * 8) {
+ sb->s_dev = 0;
+ unlock_super (sb);
+ brelse (bh);
+ printk ("EXT2-fs: #fragments per group too big: %lu\n",
+ sb->u.ext2_sb.s_frags_per_group);
+ return NULL;
+ }
+ if (sb->u.ext2_sb.s_inodes_per_group > sb->s_blocksize * 8) {
+ sb->s_dev = 0;
+ unlock_super (sb);
+ brelse (bh);
+ printk ("EXT2-fs: #inodes per group too big: %lu\n",
+ sb->u.ext2_sb.s_inodes_per_group);
+ return NULL;
+ }
+
sb->u.ext2_sb.s_groups_count = (es->s_blocks_count -
es->s_first_data_block +
EXT2_BLOCKS_PER_GROUP(sb) - 1) /
@@ -716,11 +741,11 @@ int ext2_remount (struct super_block * sb, int * flags, char * data)
return 0;
}
-void ext2_statfs (struct super_block * sb, struct statfs * buf)
+void ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
{
- long tmp;
unsigned long overhead;
unsigned long overhead_per_group;
+ struct statfs tmp;
if (test_opt (sb, MINIX_DF))
overhead = 0;
@@ -737,19 +762,15 @@ void ext2_statfs (struct super_block * sb, struct statfs * buf)
sb->u.ext2_sb.s_groups_count * overhead_per_group;
}
- put_fs_long (EXT2_SUPER_MAGIC, &buf->f_type);
- put_fs_long (sb->s_blocksize, &buf->f_bsize);
- put_fs_long (sb->u.ext2_sb.s_es->s_blocks_count - overhead,
- &buf->f_blocks);
- tmp = ext2_count_free_blocks (sb);
- put_fs_long (tmp, &buf->f_bfree);
- if (tmp >= sb->u.ext2_sb.s_es->s_r_blocks_count)
- put_fs_long (tmp - sb->u.ext2_sb.s_es->s_r_blocks_count,
- &buf->f_bavail);
- else
- put_fs_long (0, &buf->f_bavail);
- put_fs_long (sb->u.ext2_sb.s_es->s_inodes_count, &buf->f_files);
- put_fs_long (ext2_count_free_inodes (sb), &buf->f_ffree);
- put_fs_long (EXT2_NAME_LEN, &buf->f_namelen);
- /* Don't know what value to put in buf->f_fsid */
+ tmp.f_type = EXT2_SUPER_MAGIC;
+ tmp.f_bsize = sb->s_blocksize;
+ tmp.f_blocks = sb->u.ext2_sb.s_es->s_blocks_count - overhead;
+ tmp.f_bfree = ext2_count_free_blocks (sb);
+ tmp.f_bavail = tmp.f_bfree - sb->u.ext2_sb.s_es->s_r_blocks_count;
+ if (tmp.f_bfree < sb->u.ext2_sb.s_es->s_r_blocks_count)
+ tmp.f_bavail = 0;
+ tmp.f_files = sb->u.ext2_sb.s_es->s_inodes_count;
+ tmp.f_ffree = ext2_count_free_inodes (sb);
+ tmp.f_namelen = EXT2_NAME_LEN;
+ memcpy_tofs(buf, &tmp, bufsiz);
}
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index 7d85ed74c..66d4ab860 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -1,9 +1,10 @@
/*
* linux/fs/ext2/symlink.c
*
- * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
*
* from
*
diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c
index 10a1fd236..94a64f3e0 100644
--- a/fs/ext2/truncate.c
+++ b/fs/ext2/truncate.c
@@ -1,9 +1,10 @@
/*
* linux/fs/ext2/truncate.c
*
- * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
*
* from
*
@@ -45,8 +46,8 @@ static int ext2_secrm_seed = 152; /* Random generator base */
static int trunc_direct (struct inode * inode)
{
+ u32 * p;
int i, tmp;
- unsigned long * p;
struct buffer_head * bh;
unsigned long block_to_free = 0;
unsigned long free_count = 0;
@@ -102,12 +103,12 @@ repeat:
return retry;
}
-static int trunc_indirect (struct inode * inode, int offset, unsigned long * p)
+static int trunc_indirect (struct inode * inode, int offset, u32 * p)
{
int i, tmp;
struct buffer_head * bh;
struct buffer_head * ind_bh;
- unsigned long * ind;
+ u32 * ind;
unsigned long block_to_free = 0;
unsigned long free_count = 0;
int retry = 0;
@@ -134,7 +135,7 @@ repeat:
i = 0;
if (i < indirect_block)
goto repeat;
- ind = i + (unsigned long *) ind_bh->b_data;
+ ind = i + (u32 *) ind_bh->b_data;
tmp = *ind;
if (!tmp)
continue;
@@ -176,7 +177,7 @@ repeat:
}
if (free_count > 0)
ext2_free_blocks (inode->i_sb, block_to_free, free_count);
- ind = (unsigned long *) ind_bh->b_data;
+ ind = (u32 *) ind_bh->b_data;
for (i = 0; i < addr_per_block; i++)
if (*(ind++))
break;
@@ -199,11 +200,11 @@ repeat:
}
static int trunc_dindirect (struct inode * inode, int offset,
- unsigned long * p)
+ u32 * p)
{
int i, tmp;
struct buffer_head * dind_bh;
- unsigned long * dind;
+ u32 * dind;
int retry = 0;
int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
int blocks = inode->i_sb->s_blocksize / 512;
@@ -228,7 +229,7 @@ repeat:
i = 0;
if (i < dindirect_block)
goto repeat;
- dind = i + (unsigned long *) dind_bh->b_data;
+ dind = i + (u32 *) dind_bh->b_data;
tmp = *dind;
if (!tmp)
continue;
@@ -236,7 +237,7 @@ repeat:
dind);
mark_buffer_dirty(dind_bh, 1);
}
- dind = (unsigned long *) dind_bh->b_data;
+ dind = (u32 *) dind_bh->b_data;
for (i = 0; i < addr_per_block; i++)
if (*(dind++))
break;
@@ -262,7 +263,7 @@ static int trunc_tindirect (struct inode * inode)
{
int i, tmp;
struct buffer_head * tind_bh;
- unsigned long * tind, * p;
+ u32 * tind, * p;
int retry = 0;
int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
int blocks = inode->i_sb->s_blocksize / 512;
@@ -289,13 +290,13 @@ repeat:
i = 0;
if (i < tindirect_block)
goto repeat;
- tind = i + (unsigned long *) tind_bh->b_data;
+ tind = i + (u32 *) tind_bh->b_data;
retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS +
addr_per_block + (i + 1) * addr_per_block * addr_per_block,
tind);
mark_buffer_dirty(tind_bh, 1);
}
- tind = (unsigned long *) tind_bh->b_data;
+ tind = (u32 *) tind_bh->b_data;
for (i = 0; i < addr_per_block; i++)
if (*(tind++))
break;
@@ -320,6 +321,9 @@ repeat:
void ext2_truncate (struct inode * inode)
{
int retry;
+ struct buffer_head * bh;
+ int err;
+ int offset;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
@@ -331,10 +335,10 @@ void ext2_truncate (struct inode * inode)
down(&inode->i_sem);
retry = trunc_direct(inode);
retry |= trunc_indirect (inode, EXT2_IND_BLOCK,
- (unsigned long *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]);
+ (u32 *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]);
retry |= trunc_dindirect (inode, EXT2_IND_BLOCK +
EXT2_ADDR_PER_BLOCK(inode->i_sb),
- (unsigned long *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]);
+ (u32 *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]);
retry |= trunc_tindirect (inode);
up(&inode->i_sem);
if (!retry)
@@ -344,6 +348,23 @@ void ext2_truncate (struct inode * inode)
current->counter = 0;
schedule ();
}
+ /*
+ * If the file is not being truncated to a block boundary, the
+ * contents of the partial block following the end of the file must be
+ * zeroed in case it ever becomes accessible again because of
+ * subsequent file growth.
+ */
+ offset = inode->i_size % inode->i_sb->s_blocksize;
+ if (offset) {
+ bh = ext2_bread (inode, inode->i_size / inode->i_sb->s_blocksize,
+ 0, &err);
+ if (bh) {
+ memset (bh->b_data + offset, 0,
+ inode->i_sb->s_blocksize - offset);
+ mark_buffer_dirty (bh, 0);
+ brelse (bh);
+ }
+ }
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
}
diff --git a/fs/fcntl.c b/fs/fcntl.c
index d3226eb01..12f7cf489 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -63,7 +63,7 @@ asmlinkage int sys_dup(unsigned int fildes)
return dupfd(fildes,0);
}
-asmlinkage int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
+asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
struct task_struct *p;
diff --git a/fs/fifo.c b/fs/fifo.c
index ecd9bc232..e9753534a 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
+#include <linux/mm.h>
static int fifo_open(struct inode * inode,struct file * filp)
{
diff --git a/fs/hpfs/Makefile b/fs/hpfs/Makefile
index 94ab74d5d..fec1d65f4 100644
--- a/fs/hpfs/Makefile
+++ b/fs/hpfs/Makefile
@@ -14,10 +14,10 @@
.s.o:
$(AS) -o $*.o $<
-OBJS= hpfs_fs.o
+OBJS= hpfs_fs.o hpfs_caps.o
hpfs.o: $(OBJS)
- ln -f hpfs_fs.o hpfs.o
+ $(LD) -r -o hpfs.o $(OBJS)
dep:
$(CPP) -M *.c > .depend
diff --git a/fs/hpfs/hpfs.h b/fs/hpfs/hpfs.h
index 3121a415d..53d1ab2d5 100644
--- a/fs/hpfs/hpfs.h
+++ b/fs/hpfs/hpfs.h
@@ -134,8 +134,9 @@ struct hpfs_spare_block
/* The code page info pointed to by the spare block consists of an index
- block and blocks containing character maps. The following is pretty
- sketchy, but Linux doesn't use code pages so it doesn't matter. */
+ block and blocks containing uppercasing tables. I don't know what
+ these are for (CHKDSK, maybe?) -- OS/2 does not seem to use them
+ itself. Linux doesn't use them either. */
/* block pointed to by spareblock->code_page_dir */
@@ -174,7 +175,7 @@ struct code_page_data
unsigned short ix; /* index */
unsigned short code_page_number; /* code page number */
unsigned short zero1;
- unsigned char map[128]; /* map for chars 80..ff */
+ unsigned char map[128]; /* upcase table for chars 80..ff */
unsigned short zero2;
} code_page[3];
unsigned char incognita[78];
@@ -256,10 +257,11 @@ struct hpfs_dirent {
time_t creation_date; /* ctime */
unsigned ea_size; /* total EA length, bytes */
unsigned char zero1;
- unsigned char locality; /* 0=unk 1=seq 2=random 3=both */
+ unsigned char ix; /* code page index (of filename), see
+ struct code_page_data */
unsigned char namelen, name[1]; /* file name */
/* dnode_secno down; btree down pointer, if present,
- follows name on next word boundary, or maybe it's
+ follows name on next word boundary, or maybe it
precedes next dirent, which is on a word boundary. */
};
diff --git a/fs/hpfs/hpfs_caps.c b/fs/hpfs/hpfs_caps.c
new file mode 100644
index 000000000..61331c1d2
--- /dev/null
+++ b/fs/hpfs/hpfs_caps.c
@@ -0,0 +1,170 @@
+/* Capitalization rules for HPFS */
+
+/* In OS/2, HPFS filenames preserve upper and lower case letter distinctions
+ but filename matching ignores case. That is, creating a file "Foo"
+ actually creates a file named "Foo" which can be looked up as "Foo",
+ "foo", or "FOO", among other possibilities.
+
+ Also, HPFS is internationalized -- a table giving the uppercase
+ equivalent of every character is stored in the filesystem, so that
+ any national character set may be used. If several different
+ national character sets are in use, several tables are stored
+ in the filesystem.
+
+ It would be perfectly reasonable for Linux HPFS to act as a Unix
+ filesystem and match "Foo" only if asked for "Foo" exactly. But
+ the sort order of HPFS directories is case-insensitive, so Linux
+ still has to know the capitalization rules used by OS/2. Because
+ of this, it turns out to be more natural for us to be case-insensitive
+ than not.
+
+ Currently the standard character set used by Linux is Latin-1.
+ Work is underway to permit people to use UTF-8 instead, therefore
+ all code that depends on the character set is segregated here.
+
+ (It would be wonderful if Linux HPFS could be independent of what
+ character set is in use on the Linux side, but because of the
+ necessary case folding this is impossible.)
+
+ There is a map from Latin-1 into code page 850 for every printing
+ character in Latin-1. The NLS documentation of OS/2 shows that
+ everybody has 850 available unless they don't have Western latin
+ chars available at all (so fitting them to Linux without Unicode
+ is a doomed exercise).
+
+ It is not clear exactly how HPFS.IFS handles the situation when
+ multiple code pages are in use. Experiments show that
+
+ - tables on the disk give uppercasing rules for the installed code pages
+
+ - each directory entry is tagged with what code page was current
+ when that name was created
+
+ - doing just CHCP, without changing what's on the disk in any way,
+ can change what DIR reports, and what name a case-folded match
+ will match.
+
+ This means, I think, that HPFS.IFS operates in the current code
+ page, without regard to the uppercasing information recorded in
+ the tables on the disk. It does record the uppercasing rules
+ it used, perhaps for CHKDSK, but it does not appear to use them
+ itself.
+
+ So: Linux, a Latin-1 system, will operate in code page 850. We
+ recode between 850 and Latin-1 when dealing with the names actually
+ on the disk. We don't use the uppercasing tables either.
+
+ In a hypothetical UTF-8 implementation, one reasonable way to
+ proceed that matches OS/2 (for least surprise) is: do case
+ translation in UTF-8, and recode to/from one of the code pages
+ available on the mounted filesystem. Reject as invalid any name
+ containing chars that can't be represented on disk by one of the
+ code pages OS/2 is using. Recoding from on-disk names to UTF-8
+ could use the code page tags, though this is not what OS/2 does. */
+
+static const unsigned char tb_cp850_to_latin1[128] =
+{
+ 199, 252, 233, 226, 228, 224, 229, 231,
+ 234, 235, 232, 239, 238, 236, 196, 197,
+ 201, 230, 198, 244, 246, 242, 251, 249,
+ 255, 214, 220, 248, 163, 216, 215, 159,
+ 225, 237, 243, 250, 241, 209, 170, 186,
+ 191, 174, 172, 189, 188, 161, 171, 187,
+ 155, 156, 157, 144, 151, 193, 194, 192,
+ 169, 135, 128, 131, 133, 162, 165, 147,
+ 148, 153, 152, 150, 145, 154, 227, 195,
+ 132, 130, 137, 136, 134, 129, 138, 164,
+ 240, 208, 202, 203, 200, 158, 205, 206,
+ 207, 149, 146, 141, 140, 166, 204, 139,
+ 211, 223, 212, 210, 245, 213, 181, 254,
+ 222, 218, 219, 217, 253, 221, 175, 180,
+ 173, 177, 143, 190, 182, 167, 247, 184,
+ 176, 168, 183, 185, 179, 178, 142, 160,
+};
+
+#if 0
+static const unsigned char tb_latin1_to_cp850[128] =
+{
+ 186, 205, 201, 187, 200, 188, 204, 185,
+ 203, 202, 206, 223, 220, 219, 254, 242,
+ 179, 196, 218, 191, 192, 217, 195, 180,
+ 194, 193, 197, 176, 177, 178, 213, 159,
+ 255, 173, 189, 156, 207, 190, 221, 245,
+ 249, 184, 166, 174, 170, 240, 169, 238,
+ 248, 241, 253, 252, 239, 230, 244, 250,
+ 247, 251, 167, 175, 172, 171, 243, 168,
+ 183, 181, 182, 199, 142, 143, 146, 128,
+ 212, 144, 210, 211, 222, 214, 215, 216,
+ 209, 165, 227, 224, 226, 229, 153, 158,
+ 157, 235, 233, 234, 154, 237, 232, 225,
+ 133, 160, 131, 198, 132, 134, 145, 135,
+ 138, 130, 136, 137, 141, 161, 140, 139,
+ 208, 164, 149, 162, 147, 228, 148, 246,
+ 155, 151, 163, 150, 129, 236, 231, 152,
+};
+#endif
+
+#define A_GRAVE 0300
+#define THORN 0336
+#define MULTIPLY 0327
+#define a_grave 0340
+#define thorn 0376
+#define divide 0367
+
+static inline unsigned latin1_upcase (unsigned c)
+{
+ if (c - 'a' <= 'z' - 'a'
+ || (c - a_grave <= thorn - a_grave
+ && c != divide))
+ return c - 'a' + 'A';
+ else
+ return c;
+}
+
+static inline unsigned latin1_downcase (unsigned c)
+{
+ if (c - 'A' <= 'Z' - 'A'
+ || (c - A_GRAVE <= THORN - A_GRAVE
+ && c != MULTIPLY))
+ return c + 'a' - 'A';
+ else
+ return c;
+}
+
+#if 0
+static inline unsigned latin1_to_cp850 (unsigned c)
+{
+ if ((signed) c - 128 >= 0)
+ return tb_latin1_to_cp850[c - 128];
+ else
+ return c;
+}
+#endif
+
+static inline unsigned cp850_to_latin1 (unsigned c)
+{
+ if ((signed) c - 128 >= 0)
+ return tb_cp850_to_latin1[c - 128];
+ else
+ return c;
+}
+
+unsigned hpfs_char_to_upper_linux (unsigned c)
+{
+ return latin1_upcase (cp850_to_latin1 (c));
+}
+
+unsigned linux_char_to_upper_linux (unsigned c)
+{
+ return latin1_upcase (c);
+}
+
+unsigned hpfs_char_to_lower_linux (unsigned c)
+{
+ return latin1_downcase (cp850_to_latin1 (c));
+}
+
+unsigned hpfs_char_to_linux (unsigned c)
+{
+ return cp850_to_latin1 (c);
+}
diff --git a/fs/hpfs/hpfs_caps.h b/fs/hpfs/hpfs_caps.h
new file mode 100644
index 000000000..c4e49e97d
--- /dev/null
+++ b/fs/hpfs/hpfs_caps.h
@@ -0,0 +1,4 @@
+unsigned hpfs_char_to_linux (unsigned c);
+unsigned hpfs_char_to_lower_linux (unsigned c);
+unsigned hpfs_char_to_upper_linux (unsigned c);
+unsigned linux_char_to_upper_linux (unsigned c);
diff --git a/fs/hpfs/hpfs_fs.c b/fs/hpfs/hpfs_fs.c
index c05cf56ab..ec16d8af3 100644
--- a/fs/hpfs/hpfs_fs.c
+++ b/fs/hpfs/hpfs_fs.c
@@ -25,6 +25,7 @@
#include <asm/segment.h>
#include "hpfs.h"
+#include "hpfs_caps.h"
/*
* HPFS is a mixture of 512-byte blocks and 2048-byte blocks. The 2k blocks
@@ -117,9 +118,6 @@
/* notation */
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+3) & ~3)
-
#define little_ushort(x) (*(unsigned short *) &(x))
typedef void nonconst;
@@ -127,7 +125,7 @@ typedef void nonconst;
static void hpfs_read_inode(struct inode *);
static void hpfs_put_super(struct super_block *);
-static void hpfs_statfs(struct super_block *, struct statfs *);
+static void hpfs_statfs(struct super_block *, struct statfs *, int);
static int hpfs_remount_fs(struct super_block *, int *, char *);
static const struct super_operations hpfs_sops =
@@ -186,7 +184,7 @@ static const struct inode_operations hpfs_file_iops =
static int hpfs_dir_read(struct inode *inode, struct file *filp,
char *buf, int count);
static int hpfs_readdir(struct inode *inode, struct file *filp,
- struct dirent *dirent, int count);
+ void *dirent, filldir_t filldir);
static int hpfs_lookup(struct inode *, const char *, int, struct inode **);
static const struct file_operations hpfs_dir_ops =
@@ -247,8 +245,6 @@ static struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno,
struct quad_buffer_head *qbh);
static struct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp,
struct quad_buffer_head *qbh);
-static void write_one_dirent(struct dirent *dirent, const unsigned char *name,
- unsigned namelen, ino_t ino, int lowercase);
static dnode_secno dir_subdno(struct inode *inode, unsigned pos);
static struct hpfs_dirent *map_nth_dirent(dev_t dev, dnode_secno dno,
int n,
@@ -726,12 +722,13 @@ static void hpfs_put_super(struct super_block *s)
* directory band -- not exactly right but pretty analogous.
*/
-static void hpfs_statfs(struct super_block *s, struct statfs *buf)
+static void hpfs_statfs(struct super_block *s, struct statfs *buf, int bufsiz)
{
+ struct statfs tmp;
+
/*
* count the bits in the bitmaps, unless we already have
*/
-
if (s->s_hpfs_n_free == -1) {
s->s_hpfs_n_free = count_bitmap(s);
s->s_hpfs_n_free_dnodes =
@@ -741,15 +738,15 @@ static void hpfs_statfs(struct super_block *s, struct statfs *buf)
/*
* fill in the user statfs struct
*/
-
- put_fs_long(s->s_magic, &buf->f_type);
- put_fs_long(512, &buf->f_bsize);
- put_fs_long(s->s_hpfs_fs_size, &buf->f_blocks);
- put_fs_long(s->s_hpfs_n_free, &buf->f_bfree);
- put_fs_long(s->s_hpfs_n_free, &buf->f_bavail);
- put_fs_long(s->s_hpfs_dirband_size, &buf->f_files);
- put_fs_long(s->s_hpfs_n_free_dnodes, &buf->f_ffree);
- put_fs_long(254, &buf->f_namelen);
+ tmp.f_type = s->s_magic;
+ tmp.f_bsize = 512;
+ tmp.f_blocks = s->s_hpfs_fs_size;
+ tmp.f_bfree = s->s_hpfs_n_free;
+ tmp.f_bavail = s->s_hpfs_n_free;
+ tmp.f_files = s->s_hpfs_dirband_size;
+ tmp.f_ffree = s->s_hpfs_n_free_dnodes;
+ tmp.f_namelen = 254;
+ memcpy_tofs(buf, &tmp, bufsiz);
}
/*
@@ -1209,12 +1206,8 @@ static inline int memcasecmp(const unsigned char *s1, const unsigned char *s2,
if (n != 0)
do {
- unsigned c1 = *s1++;
- unsigned c2 = *s2++;
- if (c1 - 'a' < 26)
- c1 -= 040;
- if (c2 - 'a' < 26)
- c2 -= 040;
+ unsigned c1 = linux_char_to_upper_linux (*s1++);
+ unsigned c2 = hpfs_char_to_upper_linux (*s2++);
if ((t = c1 - c2) != 0)
return t;
} while (--n != 0);
@@ -1310,6 +1303,11 @@ static struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno,
* fixed, throw this out and just walk the tree and write records into
* the user buffer.)
*
+ * [ we now can handle multiple dirents, although the current libc doesn't
+ * use that. The way hpfs does this is pretty strange, as we need to do
+ * the name translation etc before calling "filldir()". This is untested,
+ * as I don't have any hpfs partitions to test against. Linus ]
+ *
* We keep track of our position in the dnode tree with a sort of
* dewey-decimal record of subtree locations. Like so:
*
@@ -1329,82 +1327,84 @@ static struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno,
* we won't have to repeatedly scan the top levels of the tree.
*/
-static int hpfs_readdir(struct inode *inode, struct file *filp,
- struct dirent *dirent, int likely_story)
+/*
+ * Translate the given name: Blam it to lowercase if the mount option said to.
+ */
+
+static void translate_hpfs_name(const unsigned char * from, int len, char * to, int lowercase)
+{
+ while (len > 0) {
+ unsigned t = *from;
+ len--;
+ if (lowercase)
+ t = hpfs_char_to_lower_linux (t);
+ else
+ t = hpfs_char_to_linux (t);
+ *to = t;
+ from++;
+ to++;
+ }
+}
+
+static int hpfs_readdir(struct inode *inode, struct file *filp, void * dirent,
+ filldir_t filldir)
{
struct quad_buffer_head qbh;
struct hpfs_dirent *de;
int namelen, lc;
ino_t ino;
+ char * tempname;
+ long old_pos;
if (inode == 0
|| inode->i_sb == 0
|| !S_ISDIR(inode->i_mode))
return -EBADF;
+ tempname = (char *) __get_free_page(GFP_KERNEL);
+ if (!tempname)
+ return -ENOMEM;
+
lc = inode->i_sb->s_hpfs_lowercase;
+ switch ((long) filp->f_pos) {
+ case -2:
+ break;
- switch ((off_t) filp->f_pos) {
case 0:
- write_one_dirent(dirent, ".", 1, inode->i_ino, lc);
+ if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
+ break;
filp->f_pos = -1;
- return ROUND_UP(NAME_OFFSET(dirent) + 2);
+ /* fall through */
case -1:
- write_one_dirent(dirent, "..", 2,
- inode->i_hpfs_parent_dir, lc);
+ if (filldir(dirent, "..", 2, filp->f_pos, inode->i_hpfs_parent_dir) < 0)
+ break;
filp->f_pos = 1;
- return ROUND_UP(NAME_OFFSET(dirent) + 3);
-
- case -2:
- return 0;
+ /* fall through */
default:
- de = map_pos_dirent(inode, &filp->f_pos, &qbh);
- if (!de) {
- filp->f_pos = -2;
- return 0;
+ for (;;) {
+ old_pos = filp->f_pos;
+ de = map_pos_dirent(inode, &filp->f_pos, &qbh);
+ if (!de) {
+ filp->f_pos = -2;
+ break;
+ }
+ namelen = de->namelen;
+ translate_hpfs_name(de->name, namelen, tempname, lc);
+ if (de->directory)
+ ino = dir_ino(de->fnode);
+ else
+ ino = file_ino(de->fnode);
+ brelse4(&qbh);
+ if (filldir(dirent, tempname, namelen, old_pos, ino) < 0) {
+ filp->f_pos = old_pos;
+ break;
+ }
}
-
- namelen = de->namelen;
- if (de->directory)
- ino = dir_ino(de->fnode);
- else
- ino = file_ino(de->fnode);
- write_one_dirent(dirent, de->name, namelen, ino, lc);
- brelse4(&qbh);
-
- return ROUND_UP(NAME_OFFSET(dirent) + namelen + 1);
}
-}
-
-/*
- * Send the given name and ino off to the user dirent struct at *dirent.
- * Blam it to lowercase if the mount option said to.
- *
- * Note that Linux d_reclen is the length of the file name, and has nothing
- * to do with the length of the dirent record.
- */
-
-static void write_one_dirent(struct dirent *dirent, const unsigned char *name,
- unsigned namelen, ino_t ino, int lowercase)
-{
- unsigned n;
-
- put_fs_long(ino, &dirent->d_ino);
- put_fs_word(namelen, &dirent->d_reclen);
-
- if (lowercase)
- for (n = namelen; n != 0;) {
- unsigned t = name[--n];
- if (t - 'A' < 26)
- t += 040;
- put_fs_byte(t, &dirent->d_name[n]);
- }
- else
- memcpy_tofs(dirent->d_name, name, namelen);
-
- put_fs_byte(0, &dirent->d_name[namelen]);
+ free_page((unsigned long) tempname);
+ return 0;
}
/*
diff --git a/fs/inode.c b/fs/inode.c
index 7278b850e..f32714aca 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -406,12 +406,18 @@ repeat:
goto repeat;
}
inode->i_count--;
+ if (inode->i_mmap) {
+ printk("iput: inode %lu on device %d/%d still has mappings.\n",
+ inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
+ inode->i_mmap = NULL;
+ }
nr_free_inodes++;
return;
}
struct inode * get_empty_inode(void)
{
+ static int ino = 0;
struct inode * inode, * best;
int i;
@@ -456,6 +462,8 @@ repeat:
inode->i_nlink = 1;
inode->i_version = ++event;
inode->i_sem.count = 1;
+ inode->i_ino = ++ino;
+ inode->i_dev = -1;
nr_free_inodes--;
if (nr_free_inodes < 0) {
printk ("VFS: get_empty_inode: bad free inode count.\n");
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 22d0f4d10..8931cd60c 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -7,6 +7,7 @@
#include <asm/segment.h>
#include <linux/sched.h>
+#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
@@ -41,11 +42,11 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
(long *) arg);
return 0;
case FIONREAD:
- error = verify_area(VERIFY_WRITE,(void *) arg,4);
+ error = verify_area(VERIFY_WRITE,(void *) arg,sizeof(int));
if (error)
return error;
put_fs_long(filp->f_inode->i_size - filp->f_pos,
- (long *) arg);
+ (int *) arg);
return 0;
}
if (filp->f_op && filp->f_op->ioctl)
diff --git a/fs/isofs/Makefile b/fs/isofs/Makefile
index a780af479..bea1ba27c 100644
--- a/fs/isofs/Makefile
+++ b/fs/isofs/Makefile
@@ -19,6 +19,9 @@ OBJS= namei.o inode.o file.o dir.o util.o rock.o symlink.o
isofs.o: $(OBJS)
$(LD) -r -o isofs.o $(OBJS)
+modules: isofs.o
+ ln -sf ../fs/isofs/isofs.o $(TOPDIR)/modules
+
dep:
$(CPP) -M *.c > .depend
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index b1934db04..55fc5b9a8 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -8,6 +8,10 @@
* isofs directory handling functions
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/errno.h>
#include <asm/segment.h>
@@ -22,12 +26,10 @@
#include <linux/sched.h>
#include <linux/locks.h>
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+3) & ~3)
+static int isofs_readdir(struct inode *, struct file *, void *, filldir_t);
-static int isofs_readdir(struct inode *, struct file *, struct dirent *, int);
-
-static struct file_operations isofs_dir_operations = {
+static struct file_operations isofs_dir_operations =
+{
NULL, /* lseek - default */
NULL, /* read */
NULL, /* write - bad */
@@ -42,14 +44,15 @@ static struct file_operations isofs_dir_operations = {
/*
* directories can handle most operations...
*/
-struct inode_operations isofs_dir_inode_operations = {
+struct inode_operations isofs_dir_inode_operations =
+{
&isofs_dir_operations, /* default directory file-ops */
- NULL, /* create */
+ NULL, /* create */
isofs_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
@@ -60,199 +63,209 @@ struct inode_operations isofs_dir_inode_operations = {
NULL /* permission */
};
-static int isofs_readdir(struct inode * inode, struct file * filp,
- struct dirent * dirent, int count)
+static int parent_inode_number(struct inode * inode, struct iso_directory_record * de)
+{
+ int inode_number = inode->i_ino;
+
+ if ((inode->i_sb->u.isofs_sb.s_firstdatazone) != inode->i_ino)
+ inode_number = inode->u.isofs_i.i_backlink;
+
+ if (inode_number != -1)
+ return inode_number;
+
+ /* This should never happen, but who knows. Try to be forgiving */
+ return isofs_lookup_grandparent(inode, find_rock_ridge_relocation(de, inode));
+}
+
+static int isofs_name_translate(char * old, int len, char * new)
+{
+ int i, c;
+
+ for (i = 0; i < len; i++) {
+ c = old[i];
+ if (!c)
+ break;
+ if (c >= 'A' && c <= 'Z')
+ c |= 0x20; /* lower case */
+
+ /* Drop trailing '.;1' (ISO9660:1988 7.5.1 requires period) */
+ if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1')
+ break;
+
+ /* Drop trailing ';1' */
+ if (c == ';' && i == len - 2 && old[i + 1] == '1')
+ break;
+
+ /* Convert remaining ';' to '.' */
+ if (c == ';')
+ c = '.';
+
+ new[i] = c;
+ }
+ return i;
+}
+
+/*
+ * This should _really_ be cleaned up some day..
+ */
+static int do_isofs_readdir(struct inode *inode, struct file *filp,
+ void *dirent, filldir_t filldir,
+ char * tmpname, struct iso_directory_record * tmpde)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
- unsigned int block,offset,i, j;
- char c = 0;
+ unsigned int block, offset;
int inode_number;
- struct buffer_head * bh;
- void * cpnt = NULL;
- unsigned int old_offset;
- int dlen, rrflag;
+ struct buffer_head *bh;
+ int len, rrflag;
int high_sierra = 0;
- char * dpnt, *dpnt1;
- struct iso_directory_record * de;
-
- dpnt1 = NULL;
- if (!inode || !S_ISDIR(inode->i_mode))
- return -EBADF;
-
+ char *name;
+ struct iso_directory_record *de;
+
offset = filp->f_pos & (bufsize - 1);
- block = isofs_bmap(inode,filp->f_pos>>bufbits);
+ block = isofs_bmap(inode, filp->f_pos >> bufbits);
- if(!block) return 0;
+ if (!block)
+ return 0;
- if(!(bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size)))
- return 0;
+ if (!(bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size)))
+ return 0;
while (filp->f_pos < inode->i_size) {
+ int de_len, next_offset;
#ifdef DEBUG
printk("Block, offset, f_pos: %x %x %x\n",
block, offset, filp->f_pos);
#endif
de = (struct iso_directory_record *) (bh->b_data + offset);
inode_number = (block << bufbits) + (offset & (bufsize - 1));
-
+
+ de_len = *(unsigned char *) de;
+
/* If the length byte is zero, we should move on to the next
CDROM sector. If we are at the end of the directory, we
kick out of the while loop. */
-
- if (*((unsigned char *) de) == 0) {
+
+ if (de_len == 0) {
brelse(bh);
- offset = 0;
filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
+ ISOFS_BLOCK_SIZE);
- block = isofs_bmap(inode,(filp->f_pos)>>bufbits);
- if (!block
- || !(bh = breada(inode->i_dev, block, bufsize, filp->f_pos,
- inode->i_size)))
+ offset = 0;
+ block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
+ if (!block)
+ return 0;
+ bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size);
+ if (!bh)
return 0;
continue;
}
/* Make sure that the entire directory record is in the
current bh block.
- If not, we malloc a buffer, and put the two halves together,
- so that we can cleanly read the block */
-
- old_offset = offset;
- offset += *((unsigned char *) de);
- filp->f_pos += *((unsigned char *) de);
-
- if (offset > bufsize) {
- unsigned int frag1;
- frag1 = bufsize - old_offset;
- cpnt = kmalloc(*((unsigned char *) de),GFP_KERNEL);
- if (!cpnt) return 0;
- memcpy(cpnt, bh->b_data + old_offset, frag1);
- de = (struct iso_directory_record *) ((char *)cpnt);
+ If not, put the two halves together in "tmpde" */
+ next_offset = offset + de_len;
+ if (next_offset > bufsize) {
+ next_offset &= (bufsize - 1);
+ memcpy(tmpde, de, bufsize - offset);
brelse(bh);
- offset = filp->f_pos & (bufsize - 1);
- block = isofs_bmap(inode,(filp->f_pos)>> bufbits);
- if (!block
- || !(bh = breada(inode->i_dev, block, bufsize,
- filp->f_pos, inode->i_size))) {
- kfree(cpnt);
+ block = isofs_bmap(inode, (filp->f_pos + de_len) >> bufbits);
+ if (!block)
return 0;
- };
- memcpy((char *)cpnt+frag1, bh->b_data, offset);
+ bh = breada(inode->i_dev, block, bufsize, filp->f_pos+de_len, inode->i_size);
+ if (!bh)
+ return 0;
+ memcpy(bufsize - offset + (char *) tmpde, bh->b_data, next_offset);
+ de = tmpde;
}
-
- /* Handle the case of the '.' directory */
+ offset = next_offset;
- rrflag = 0;
- i = 1;
+ /* Handle the case of the '.' directory */
if (de->name_len[0] == 1 && de->name[0] == 0) {
- put_fs_byte('.',dirent->d_name);
- inode_number = inode->i_ino;
- dpnt = ".";
+ if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
+ break;
+ filp->f_pos += de_len;
+ continue;
}
-
+
/* Handle the case of the '..' directory */
-
- else if (de->name_len[0] == 1 && de->name[0] == 1) {
- put_fs_byte('.',dirent->d_name);
- put_fs_byte('.',dirent->d_name+1);
- i = 2;
- dpnt = "..";
- if((inode->i_sb->u.isofs_sb.s_firstdatazone) != inode->i_ino)
- inode_number = inode->u.isofs_i.i_backlink;
- else
- inode_number = inode->i_ino;
-
- /* This should never happen, but who knows. Try to be forgiving */
- if(inode_number == -1) {
- inode_number =
- isofs_lookup_grandparent(inode,
- find_rock_ridge_relocation(de, inode));
- if(inode_number == -1){ /* Should never happen */
- printk("Backlink not properly set.\n");
- goto out;
- };
- }
+ if (de->name_len[0] == 1 && de->name[0] == 1) {
+ inode_number = parent_inode_number(inode, de);
+ if (inode_number == -1)
+ break;
+ if (filldir(dirent, "..", 2, filp->f_pos, inode_number) < 0)
+ break;
+ filp->f_pos += de_len;
+ continue;
}
-
+
/* Handle everything else. Do name translation if there
is no Rock Ridge NM field. */
-
- else {
- /* Do not report hidden or associated files */
- high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
- if (de->flags[-high_sierra] & 5) {
- if (cpnt) {
- kfree(cpnt);
- cpnt = NULL;
- };
- continue;
- }
- dlen = de->name_len[0];
- dpnt = de->name;
- i = dlen;
- rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, inode);
- if (rrflag) {
- if (rrflag == -1) { /* This is a rock ridge reloc dir */
- if (cpnt) {
- kfree(cpnt);
- cpnt = NULL;
- };
- continue;
- };
- i = dlen;
+
+ if (inode->i_sb->u.isofs_sb.s_unhide == 'n') {
+ /* Do not report hidden or associated files */
+ high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
+ if (de->flags[-high_sierra] & 5) {
+ filp->f_pos += de_len;
+ continue;
}
- else
- if(inode->i_sb->u.isofs_sb.s_mapping == 'n') {
- dpnt1 = dpnt;
- dpnt = kmalloc(dlen, GFP_KERNEL);
- if (!dpnt) goto out;
- for (i = 0; i < dlen && i < NAME_MAX; i++) {
- if (!(c = dpnt1[i])) break;
- if (c >= 'A' && c <= 'Z') c |= 0x20; /* lower case */
- if (c == '.' && i == dlen-3 && de->name[i+1] == ';' && de->name[i+2] == '1')
- break; /* Drop trailing '.;1' (ISO9660:1988 7.5.1 requires period) */
- if (c == ';' && i == dlen-2 && de->name[i+1] == '1')
- break; /* Drop trailing ';1' */
- if (c == ';') c = '.'; /* Convert remaining ';' to '.' */
- dpnt[i] = c;
- }
- }
- for(j=0; j<i; j++)
- put_fs_byte(dpnt[j],j+dirent->d_name); /* And save it */
- if(dpnt1) {
- kfree(dpnt);
- dpnt = dpnt1;
+ }
+
+ /* Check Rock Ridge name translation.. */
+ len = de->name_len[0];
+ name = de->name;
+ rrflag = get_rock_ridge_filename(de, &name, &len, inode);
+ if (rrflag) {
+ /* rrflag == 1 means that we have a new name (kmalloced) */
+ if (rrflag == 1) {
+ rrflag = filldir(dirent, name, len, filp->f_pos, inode_number);
+ kfree(name); /* this was allocated in get_r_r_filename.. */
+ if (rrflag < 0)
+ break;
}
-
- dcache_add(inode, dpnt, i, inode_number);
- };
-#if 0
- printk("Nchar: %d\n",i);
-#endif
+ filp->f_pos += de_len;
+ continue;
+ }
- if (rrflag) kfree(dpnt);
- if (cpnt) {
- kfree(cpnt);
- cpnt = NULL;
- };
-
- if (i) {
- put_fs_long(inode_number, &dirent->d_ino);
- put_fs_byte(0,i+dirent->d_name);
- put_fs_word(i,&dirent->d_reclen);
- brelse(bh);
- return ROUND_UP(NAME_OFFSET(dirent) + i + 1);
+ if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
+ len = isofs_name_translate(name, len, tmpname);
+ if (filldir(dirent, tmpname, len, filp->f_pos, inode_number) < 0)
+ break;
+ filp->f_pos += de_len;
+ continue;
}
- }
- /* We go here for any condition we cannot handle. We also drop through
- to here at the end of the directory. */
- out:
- if (cpnt)
- kfree(cpnt);
+
+ if (filldir(dirent, name, len, filp->f_pos, inode_number) < 0)
+ break;
+
+ filp->f_pos += de_len;
+ continue;
+ }
brelse(bh);
return 0;
}
+/*
+ * Handle allocation of temporary space for name translation and
+ * handling split directory entries.. The real work is done by
+ * "do_isofs_readdir()".
+ */
+static int isofs_readdir(struct inode *inode, struct file *filp,
+ void *dirent, filldir_t filldir)
+{
+ int result;
+ char * tmpname;
+ struct iso_directory_record * tmpde;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -EBADF;
+
+ tmpname = (char *) __get_free_page(GFP_KERNEL);
+ if (!tmpname)
+ return -ENOMEM;
+ tmpde = (struct iso_directory_record *) (tmpname+256);
+ result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
+ free_page((unsigned long) tmpname);
+ return result;
+}
diff --git a/fs/isofs/file.c b/fs/isofs/file.c
index ee0877d7b..831bfeaf4 100644
--- a/fs/isofs/file.c
+++ b/fs/isofs/file.c
@@ -8,6 +8,10 @@
* isofs regular file handling primitives
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <asm/system.h>
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index c1754e337..db3200bc6 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -6,6 +6,14 @@
* (C) 1991 Linus Torvalds - minix filesystem
*/
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/iso_fs.h>
@@ -16,6 +24,7 @@
#include <linux/locks.h>
#include <linux/malloc.h>
#include <linux/errno.h>
+#include <linux/cdrom.h>
#include <asm/system.h>
#include <asm/segment.h>
@@ -35,6 +44,7 @@ void isofs_put_super(struct super_block *sb)
#endif
sb->s_dev = 0;
unlock_super(sb);
+ MOD_DEC_USE_COUNT;
return;
}
@@ -53,8 +63,10 @@ struct iso9660_options{
char map;
char rock;
char cruft;
+ char unhide;
unsigned char conversion;
unsigned int blocksize;
+ mode_t mode;
gid_t gid;
uid_t uid;
};
@@ -66,8 +78,10 @@ static int parse_options(char *options, struct iso9660_options * popt)
popt->map = 'n';
popt->rock = 'y';
popt->cruft = 'n';
- popt->conversion = 'a';
+ popt->unhide = 'n';
+ popt->conversion = 'b'; /* default: no conversion */
popt->blocksize = 1024;
+ popt->mode = S_IRUGO;
popt->gid = 0;
popt->uid = 0;
if (!options) return 1;
@@ -76,6 +90,10 @@ static int parse_options(char *options, struct iso9660_options * popt)
popt->rock = 'n';
continue;
};
+ if (strncmp(this_char,"unhide",6) == 0) {
+ popt->unhide = 'y';
+ continue;
+ };
if (strncmp(this_char,"cruft",5) == 0) {
popt->cruft = 'y';
continue;
@@ -100,6 +118,7 @@ static int parse_options(char *options, struct iso9660_options * popt)
}
else if (value &&
(!strcmp(this_char,"block") ||
+ !strcmp(this_char,"mode") ||
!strcmp(this_char,"uid") ||
!strcmp(this_char,"gid"))) {
char * vpnt = value;
@@ -122,6 +141,9 @@ static int parse_options(char *options, struct iso9660_options * popt)
case 'g':
popt->gid = ivalue;
break;
+ case 'm':
+ popt->mode = ivalue;
+ break;
}
}
else return 0;
@@ -129,14 +151,53 @@ static int parse_options(char *options, struct iso9660_options * popt)
return 1;
}
+
+static unsigned int isofs_get_last_session(int dev)
+{
+ struct cdrom_multisession ms_info;
+ unsigned int vol_desc_start;
+ struct inode inode_fake;
+ extern struct file_operations * get_blkfops(unsigned int);
+ int i;
+
+ /*
+ * look if the driver can tell the multi session redirection value
+ * <emoenke@gwdg.de>
+ */
+ vol_desc_start=0;
+ if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
+ {
+ inode_fake.i_rdev=dev;
+ ms_info.addr_format=CDROM_LBA;
+ set_fs(KERNEL_DS);
+ i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
+ NULL,
+ CDROMMULTISESSION,
+ (unsigned long) &ms_info);
+ set_fs(USER_DS);
+#if 0
+ printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
+ if (i==0)
+ {
+ printk("isofs.inode: XA disk: %s\n", ms_info.xa_flag ? "yes":"no");
+ printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
+ }
+#endif 0
+ if ((i==0)&&(ms_info.xa_flag)) vol_desc_start=ms_info.addr.lba;
+ }
+ return vol_desc_start;
+}
+
struct super_block *isofs_read_super(struct super_block *s,void *data,
int silent)
{
- struct buffer_head *bh;
+ struct buffer_head *bh=NULL;
int iso_blknum;
unsigned int blocksize_bits;
int high_sierra;
int dev=s->s_dev;
+ unsigned int vol_desc_start;
+
struct iso_volume_descriptor *vdp;
struct hs_volume_descriptor *hdp;
@@ -147,8 +208,11 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
struct iso9660_options opt;
+ MOD_INC_USE_COUNT;
+
if (!parse_options((char *) data,&opt)) {
s->s_dev = 0;
+ MOD_DEC_USE_COUNT;
return NULL;
}
@@ -156,6 +220,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
printk("map = %c\n", opt.map);
printk("rock = %c\n", opt.rock);
printk("cruft = %c\n", opt.cruft);
+ printk("unhide = %c\n", opt.unhide);
printk("conversion = %c\n", opt.conversion);
printk("blocksize = %d\n", opt.blocksize);
printk("gid = %d\n", opt.gid);
@@ -176,12 +241,18 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */
- for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) {
+ vol_desc_start = isofs_get_last_session(dev);
+
+ for (iso_blknum = vol_desc_start+16; iso_blknum < vol_desc_start+100; iso_blknum++) {
+#if 0
+ printk("isofs.inode: iso_blknum=%d\n", iso_blknum);
+#endif 0
if (!(bh = bread(dev, iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits), opt.blocksize))) {
s->s_dev=0;
printk("isofs_read_super: bread failed, dev 0x%x iso_blknum %d\n",
dev, iso_blknum);
unlock_super(s);
+ MOD_DEC_USE_COUNT;
return NULL;
}
@@ -214,11 +285,12 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
brelse(bh);
}
- if(iso_blknum == 100) {
+ if(iso_blknum == vol_desc_start + 100) {
if (!silent)
printk("Unable to identify CD-ROM format.\n");
s->s_dev = 0;
unlock_super(s);
+ MOD_DEC_USE_COUNT;
return NULL;
};
@@ -288,8 +360,14 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 1 : 0);
s->u.isofs_sb.s_conversion = opt.conversion;
s->u.isofs_sb.s_cruft = opt.cruft;
+ s->u.isofs_sb.s_unhide = opt.unhide;
s->u.isofs_sb.s_uid = opt.uid;
s->u.isofs_sb.s_gid = opt.gid;
+ /*
+ * It would be incredibly stupid to allow people to mark every file on the disk
+ * as suid, so we merely allow them to set the default permissions.
+ */
+ s->u.isofs_sb.s_mode = opt.mode & 0777;
s->s_blocksize = opt.blocksize;
s->s_blocksize_bits = blocksize_bits;
s->s_mounted = iget(s, isonum_733 (rootp->extent) << s -> u.isofs_sb.s_log_zone_size);
@@ -298,28 +376,34 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
if (!(s->s_mounted)) {
s->s_dev=0;
printk("get root inode failed\n");
+ MOD_DEC_USE_COUNT;
return NULL;
}
- if(!check_disk_change(s->s_dev)) return s;
+ if(!check_disk_change(s->s_dev)) {
+ return s;
+ }
out: /* Kick out for various error conditions */
brelse(bh);
s->s_dev = 0;
unlock_super(s);
+ MOD_DEC_USE_COUNT;
return NULL;
}
-void isofs_statfs (struct super_block *sb, struct statfs *buf)
+void isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
{
- put_fs_long(ISOFS_SUPER_MAGIC, &buf->f_type);
- put_fs_long(1 << ISOFS_BLOCK_BITS, &buf->f_bsize);
- put_fs_long(sb->u.isofs_sb.s_nzones, &buf->f_blocks);
- put_fs_long(0, &buf->f_bfree);
- put_fs_long(0, &buf->f_bavail);
- put_fs_long(sb->u.isofs_sb.s_ninodes, &buf->f_files);
- put_fs_long(0, &buf->f_ffree);
- put_fs_long(NAME_MAX, &buf->f_namelen);
- /* Don't know what value to put in buf->f_fsid */
+ struct statfs tmp;
+
+ tmp.f_type = ISOFS_SUPER_MAGIC;
+ tmp.f_bsize = 1 << ISOFS_BLOCK_BITS;
+ tmp.f_blocks = sb->u.isofs_sb.s_nzones;
+ tmp.f_bfree = 0;
+ tmp.f_bavail = 0;
+ tmp.f_files = sb->u.isofs_sb.s_ninodes;
+ tmp.f_ffree = 0;
+ tmp.f_namelen = NAME_MAX;
+ memcpy_tofs(buf, &tmp, bufsiz);
}
int isofs_bmap(struct inode * inode,int block)
@@ -378,9 +462,6 @@ void isofs_read_inode(struct inode * inode)
raw_inode = ((struct iso_directory_record *) pnt);
}
- inode->i_mode = S_IRUGO; /* Everybody gets to read the file. */
- inode->i_nlink = 1;
-
if (raw_inode->flags[-high_sierra] & 2) {
inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
inode->i_nlink = 1; /* Set to 1. We know there are 2, but
@@ -389,7 +470,7 @@ void isofs_read_inode(struct inode * inode)
easier to give 1 which tells find to
do it the hard way. */
} else {
- inode->i_mode = S_IRUGO; /* Everybody gets to read the file. */
+ inode->i_mode = inode->i_sb->u.isofs_sb.s_mode; /* Everybody gets to read the file. */
inode->i_nlink = 1;
inode->i_mode |= S_IFREG;
/* If there are no periods in the name, then set the execute permission bit */
@@ -705,3 +786,25 @@ void leak_check_brelse(struct buffer_head * bh){
}
#endif
+
+#ifdef MODULE
+
+char kernel_version[] = UTS_RELEASE;
+
+static struct file_system_type iso9660_fs_type = {
+ isofs_read_super, "iso9660", 1, NULL
+};
+
+int init_module(void)
+{
+ register_filesystem(&iso9660_fs_type);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unregister_filesystem(&iso9660_fs_type);
+}
+
+#endif
+
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index 1473b1b7f..02d01171f 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -6,6 +6,10 @@
* (C) 1991 Linus Torvalds - minix filesystem
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/sched.h>
#include <linux/iso_fs.h>
#include <linux/kernel.h>
@@ -69,7 +73,6 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
unsigned int old_offset;
unsigned int backlink;
int dlen, rrflag, match;
- int high_sierra = 0;
char * dpnt;
struct iso_directory_record * de;
char c;
@@ -151,16 +154,6 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
backlink = 0;
}
- /* Do not report hidden or associated files */
- high_sierra = dir->i_sb->u.isofs_sb.s_high_sierra;
- if (de->flags[-high_sierra] & 5) {
- if (cpnt) {
- kfree(cpnt);
- cpnt = NULL;
- };
- continue;
- }
-
dlen = de->name_len[0];
dpnt = de->name;
/* Now convert the filename in the buffer to lower case */
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index 686c1d910..b902d8f24 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -5,7 +5,10 @@
*
* Rock Ridge Extensions to iso9660
*/
-#include <linux/config.h>
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/iso_fs.h>
@@ -302,7 +305,18 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
{ int high, low;
high = isonum_733(rr->u.PN.dev_high);
low = isonum_733(rr->u.PN.dev_low);
- inode->i_rdev = ((high << 8) | (low & 0xff)) & 0xffff;
+ /*
+ * The Rock Ridge standard specifies that if sizeof(dev_t) <=4,
+ * then the high field is unused, and the device number is completely
+ * stored in the low field. Some writers may ignore this subtlety,
+ * and as a result we test to see if the entire device number is
+ * stored in the low field, and use that.
+ */
+ if(MINOR(low) != low && high == 0) {
+ inode->i_rdev = low;
+ } else {
+ inode->i_rdev = MKDEV(high, low);
+ }
};
break;
case SIG('T','F'):
diff --git a/fs/isofs/symlink.c b/fs/isofs/symlink.c
index fa4a45ba6..d159e424f 100644
--- a/fs/isofs/symlink.c
+++ b/fs/isofs/symlink.c
@@ -9,6 +9,10 @@
* extensions to iso9660
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/errno.h>
diff --git a/fs/isofs/util.c b/fs/isofs/util.c
index dbeee868d..ba432b391 100644
--- a/fs/isofs/util.c
+++ b/fs/isofs/util.c
@@ -9,6 +9,10 @@
* the bsd386 iso9660 filesystem, by Pace Williamson.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
int
isonum_711 (char * p)
diff --git a/fs/locks.c b/fs/locks.c
index d1de73ad0..9b64fa185 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2,23 +2,61 @@
* linux/fs/locks.c
*
* Provide support for fcntl()'s F_GETLK, F_SETLK, and F_SETLKW calls.
- * Doug Evans, 92Aug07, dje@sspiff.uucp.
+ * Doug Evans (dje@spiff.uucp), August 07, 1992
*
- * Deadlock Detection added by Kelly Carmichael, kelly@[142.24.8.65]
- * September 17, 1994.
- *
- * FIXME: one thing isn't handled yet:
+ * Deadlock detection added.
+ * FIXME: one thing isn't handled yet:
* - mandatory locks (requires lots of changes elsewhere)
+ * Kelly Carmichael (kelly@[142.24.8.65]), September 17, 1994.
*
- * Edited by Kai Petzke, wpp@marie.physik.tu-berlin.de
- *
+ * Miscellaneous edits, and a total rewrite of posix_lock_file() code.
+ * Kai Petzke (wpp@marie.physik.tu-berlin.de), 1994
+ *
* Converted file_lock_table to a linked list from an array, which eliminates
- * the limits on how many active file locks are open - Chad Page
- * (pageone@netcom.com), November 27, 1994
+ * the limits on how many active file locks are open.
+ * Chad Page (pageone@netcom.com), November 27, 1994
+ *
+ * Removed dependency on file descriptors. dup()'ed file descriptors now
+ * get the same locks as the original file descriptors, and a close() on
+ * any file descriptor removes ALL the locks on the file for the current
+ * process. Since locks still depend on the process id, locks are inherited
+ * after an exec() but not after a fork(). This agrees with POSIX, and both
+ * BSD and SVR4 practice.
+ * Andy Walker (andy@keo.kvaerner.no), February 14, 1995
+ *
+ * Scrapped free list which is redundant now that we allocate locks
+ * dynamically with kmalloc()/kfree().
+ * Andy Walker (andy@keo.kvaerner.no), February 21, 1995
+ *
+ * Implemented two lock personalities - F_FLOCK and F_POSIX.
+ *
+ * F_POSIX locks are created with calls to fcntl() and lockf() through the
+ * fcntl() system call. They have the semantics described above.
+ *
+ * F_FLOCK locks are created with calls to flock(), through the flock()
+ * system call, which is new. Old C libraries implement flock() via fcntl()
+ * and will continue to use the old, broken implementation.
+ *
+ * F_FLOCK locks follow the 4.4 BSD flock() semantics. They are associated
+ * with a file pointer (filp). As a result they can be shared by a parent
+ * process and its children after a fork(). They are removed when the last
+ * file descriptor referring to the file pointer is closed (unless explicitly
+ * unlocked).
+ *
+ * F_FLOCK locks never deadlock, an existing lock is always removed before
+ * upgrading from shared to exclusive (or vice versa). When this happens
+ * any processes blocked by the current lock are woken up and allowed to
+ * run before the new lock is applied.
+ *
+ * NOTE:
+ * I do not intend to implement mandatory locks unless demand is *HUGE*.
+ * They are not in BSD, and POSIX.1 does not require them. I have never
+ * seen any public code that relied on them. As Kelly Carmichael suggests
+ * above, mandatory locks requires lots of changes elsewhere and I am
+ * reluctant to start something so drastic for so little gain.
+ * Andy Walker (andy@keo.kvaerner.no), June 09, 1995
*/
-#define DEADLOCK_DETECTION
-
#include <asm/segment.h>
#include <linux/malloc.h>
@@ -30,21 +68,53 @@
#define OFFSET_MAX ((off_t)0x7fffffff) /* FIXME: move elsewhere? */
-static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l,
- unsigned int fd);
-static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl);
-static int overlap(struct file_lock *fl1, struct file_lock *fl2);
-static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd);
-static struct file_lock *alloc_lock(struct file_lock **pos, struct file_lock *fl,
- unsigned int fd);
-static void free_lock(struct file_lock **fl);
-#ifdef DEADLOCK_DETECTION
-int locks_deadlocked(int my_pid,int blocked_pid);
-#endif
+static int flock_make_lock(struct file *filp, struct file_lock *fl,
+ unsigned int cmd);
+static int posix_make_lock(struct file *filp, struct file_lock *fl,
+ struct flock *l);
+static int flock_locks_conflict(struct file_lock *caller_fl,
+ struct file_lock *sys_fl);
+static int posix_locks_conflict(struct file_lock *caller_fl,
+ struct file_lock *sys_fl);
+static int locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl);
+static int flock_lock_file(struct file *filp, struct file_lock *caller,
+ unsigned int wait);
+static int posix_lock_file(struct file *filp, struct file_lock *caller,
+ unsigned int wait);
+static int posix_locks_deadlock(struct task_struct *my_task,
+ struct task_struct *blocked_task);
+static int locks_overlap(struct file_lock *fl1, struct file_lock *fl2);
+
+static struct file_lock *locks_alloc_lock(struct file_lock *fl);
+static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl);
+static void locks_delete_lock(struct file_lock **fl, unsigned int wait);
+static void locks_insert_block(struct file_lock **block, struct file_lock *fl);
static struct file_lock *file_lock_table = NULL;
-static struct file_lock *file_lock_free_list = NULL;
+/* flock() system call entry point. Apply a FLOCK style locks to
+ * an open file descriptor.
+ */
+asmlinkage int sys_flock(unsigned int fd, unsigned int cmd)
+{
+ struct file_lock file_lock;
+ struct file *filp;
+
+ if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
+ return (-EBADF);
+
+ if (!flock_make_lock(filp, &file_lock, cmd))
+ return (-EINVAL);
+
+ if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
+ return (-EBADF);
+
+ return (flock_lock_file(filp, &file_lock, cmd & LOCK_UN ? 0 : cmd & LOCK_NB ? 0 : 1));
+}
+
+/* Report the first existing locks that would conflict with l. This implements
+ * the F_GETLK command of fcntl().
+ */
int fcntl_getlk(unsigned int fd, struct flock *l)
{
int error;
@@ -52,59 +122,65 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
struct file *filp;
struct file_lock *fl,file_lock;
- if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
- return -EBADF;
- error = verify_area(VERIFY_WRITE,l, sizeof(*l));
+ if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
+ return (-EBADF);
+ error = verify_area(VERIFY_WRITE, l, sizeof(*l));
if (error)
- return error;
+ return (error);
+
memcpy_fromfs(&flock, l, sizeof(flock));
- if (flock.l_type == F_UNLCK)
- return -EINVAL;
- if (!copy_flock(filp, &file_lock, &flock, fd))
- return -EINVAL;
+ if ((flock.l_type == F_UNLCK) || (flock.l_type == F_EXLCK) ||
+ (flock.l_type == F_SHLCK))
+ return (-EINVAL);
+
+ if (!posix_make_lock(filp, &file_lock, &flock))
+ return (-EINVAL);
for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
- if (conflict(&file_lock, fl)) {
+ if (posix_locks_conflict(&file_lock, fl)) {
flock.l_pid = fl->fl_owner->pid;
flock.l_start = fl->fl_start;
flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
fl->fl_end - fl->fl_start + 1;
- flock.l_whence = fl->fl_whence;
+ flock.l_whence = 0;
flock.l_type = fl->fl_type;
memcpy_tofs(l, &flock, sizeof(flock));
- return 0;
+ return (0);
}
}
flock.l_type = F_UNLCK; /* no conflict found */
memcpy_tofs(l, &flock, sizeof(flock));
- return 0;
+ return (0);
}
-/*
- * This function implements both F_SETLK and F_SETLKW.
+/* Apply the lock described by l to an open file descriptor. This implements
+ * both the F_SETLK and F_SETLKW commands of fcntl(). It also emulates flock()
+ * in a pretty broken way for older C libraries.
*/
-
int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
{
int error;
struct file *filp;
- struct file_lock *fl,file_lock;
+ struct file_lock file_lock;
struct flock flock;
/*
* Get arguments and validate them ...
*/
- if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
- return -EBADF;
+ if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
+ return (-EBADF);
+
error = verify_area(VERIFY_READ, l, sizeof(*l));
if (error)
- return error;
+ return (error);
+
memcpy_fromfs(&flock, l, sizeof(flock));
- if (!copy_flock(filp, &file_lock, &flock, fd))
- return -EINVAL;
- switch (file_lock.fl_type) {
+ if (!posix_make_lock(filp, &file_lock, &flock))
+ return (-EINVAL);
+
+ switch (flock.l_type) {
case F_RDLCK :
if (!(filp->f_mode & 1))
return -EBADF;
@@ -114,178 +190,287 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
return -EBADF;
break;
case F_SHLCK :
- if (!(filp->f_mode & 3))
- return -EBADF;
- file_lock.fl_type = F_RDLCK;
- break;
case F_EXLCK :
if (!(filp->f_mode & 3))
return -EBADF;
- file_lock.fl_type = F_WRLCK;
break;
case F_UNLCK :
break;
}
-
- /*
- * Scan for a conflicting lock ...
- */
-
- if (file_lock.fl_type != F_UNLCK) {
-repeat:
- for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
- if (!conflict(&file_lock, fl))
- continue;
- /*
- * File is locked by another process. If this is
- * F_SETLKW wait for the lock to be released.
- */
- if (cmd == F_SETLKW) {
- if (current->signal & ~current->blocked)
- return -ERESTARTSYS;
-#ifdef DEADLOCK_DETECTION
- if (locks_deadlocked(file_lock.fl_owner->pid,fl->fl_owner->pid)) return -EDEADLOCK;
-#endif
- interruptible_sleep_on(&fl->fl_wait);
- if (current->signal & ~current->blocked)
- return -ERESTARTSYS;
- goto repeat;
- }
- return -EAGAIN;
- }
- }
-
- /*
- * Lock doesn't conflict with any other lock ...
- */
-
- return lock_it(filp, &file_lock, fd);
-}
-
-#ifdef DEADLOCK_DETECTION
-/*
- * This function tests for deadlock condition before putting a process to sleep
- * this detection scheme is recursive... we may need some test as to make it
- * exit if the function gets stuck due to bad lock data.
- */
-
-int locks_deadlocked(int my_pid,int blocked_pid)
-{
- int ret_val;
- struct wait_queue *dlock_wait;
- struct file_lock *fl;
- for (fl = file_lock_table; fl != NULL; fl = fl->fl_nextlink) {
- if (fl->fl_owner == NULL) continue; /* not a used lock */
- if (fl->fl_owner->pid != my_pid) continue;
- if (fl->fl_wait == NULL) continue; /* no queues */
- dlock_wait = fl->fl_wait;
- do {
- if (dlock_wait->task != NULL) {
- if (dlock_wait->task->pid == blocked_pid) return -EDEADLOCK;
- ret_val = locks_deadlocked(dlock_wait->task->pid,blocked_pid);
- if (ret_val) return -EDEADLOCK;
- }
- dlock_wait = dlock_wait->next;
- } while (dlock_wait != NULL);
- }
- return 0;
+
+ return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW));
}
-#endif
-/*
- * This function is called when the file is closed.
+/* This function is called when the file is closed.
*/
-
-void fcntl_remove_locks(struct task_struct *task, struct file *filp,
- unsigned int fd)
+void locks_remove_locks(struct task_struct *task, struct file *filp)
{
struct file_lock *fl;
struct file_lock **before;
- /* Find first lock owned by caller ... */
-
+ /* For POSIX locks we free all locks on this file for the given task.
+ * For FLOCK we only free locks on this *open* file if it is the last
+ * close on that file.
+ */
before = &filp->f_inode->i_flock;
- while ((fl = *before) && (task != fl->fl_owner || fd != fl->fl_fd))
- before = &fl->fl_next;
-
- /* The list is sorted by owner and fd ... */
+ while ((fl = *before) != NULL) {
+ if (((fl->fl_flags == F_POSIX) && (fl->fl_owner == task)) ||
+ ((fl->fl_flags == F_FLOCK) && (fl->fl_file == filp) &&
+ (filp->f_count == 1)))
+ locks_delete_lock(before, 0);
+ else
+ before = &fl->fl_next;
+ }
- while ((fl = *before) && task == fl->fl_owner && fd == fl->fl_fd)
- free_lock(before);
+ return;
}
-/*
- * Verify a "struct flock" and copy it to a "struct file_lock" ...
- * Result is a boolean indicating success.
+/* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX
+ * style lock.
*/
-
-static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l,
- unsigned int fd)
+static int posix_make_lock(struct file *filp, struct file_lock *fl,
+ struct flock *l)
{
off_t start;
if (!filp->f_inode) /* just in case */
- return 0;
- if (l->l_type != F_UNLCK && l->l_type != F_RDLCK && l->l_type != F_WRLCK
- && l->l_type != F_SHLCK && l->l_type != F_EXLCK)
- return 0;
+ return (0);
+
+ switch (l->l_type) {
+ case F_RDLCK :
+ case F_WRLCK :
+ case F_UNLCK :
+ fl->fl_type = l->l_type;
+ break;
+ case F_SHLCK :
+ fl->fl_type = F_RDLCK;
+ break;
+ case F_EXLCK :
+ fl->fl_type = F_WRLCK;
+ break;
+ default :
+ return (0);
+ }
+
switch (l->l_whence) {
- case 0 /*SEEK_SET*/ : start = 0; break;
- case 1 /*SEEK_CUR*/ : start = filp->f_pos; break;
- case 2 /*SEEK_END*/ : start = filp->f_inode->i_size; break;
- default : return 0;
+ case 0 : /*SEEK_SET*/
+ start = 0;
+ break;
+ case 1 : /*SEEK_CUR*/
+ start = filp->f_pos;
+ break;
+ case 2 : /*SEEK_END*/
+ start = filp->f_inode->i_size;
+ break;
+ default :
+ return (0);
}
- if ((start += l->l_start) < 0 || l->l_len < 0)
- return 0;
- fl->fl_type = l->l_type;
+
+ if (((start += l->l_start) < 0) || (l->l_len < 0))
+ return (0);
fl->fl_start = start; /* we record the absolute position */
- fl->fl_whence = 0; /* FIXME: do we record {l_start} as passed? */
- if (l->l_len == 0 || (fl->fl_end = start + l->l_len - 1) < 0)
+ if ((l->l_len == 0) || ((fl->fl_end = start + l->l_len - 1) < 0))
fl->fl_end = OFFSET_MAX;
+
+ fl->fl_flags = F_POSIX;
+ fl->fl_file = filp;
fl->fl_owner = current;
- fl->fl_fd = fd;
fl->fl_wait = NULL; /* just for cleanliness */
- return 1;
+
+ return (1);
}
-/*
- * Determine if lock {sys_fl} blocks lock {caller_fl} ...
+/* Verify a call to flock() and fill in a file_lock structure with an appropriate
+ * FLOCK lock.
*/
+static int flock_make_lock(struct file *filp, struct file_lock *fl,
+ unsigned int cmd)
+{
+ if (!filp->f_inode) /* just in case */
+ return (0);
+
+ switch (cmd & ~LOCK_NB) {
+ case LOCK_SH :
+ fl->fl_type = F_RDLCK;
+ break;
+ case LOCK_EX :
+ fl->fl_type = F_WRLCK;
+ break;
+ case LOCK_UN :
+ fl->fl_type = F_UNLCK;
+ break;
+ default :
+ return (0);
+ }
+
+ fl->fl_flags = F_FLOCK;
+ fl->fl_start = 0;
+ fl->fl_end = OFFSET_MAX;
+ fl->fl_file = filp;
+ fl->fl_owner = current;
+ fl->fl_wait = NULL; /* just for cleanliness */
+
+ return (1);
+}
-static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
+/* Determine if lock sys_fl blocks lock caller_fl. POSIX specific checking
+ * before calling the locks_conflict().
+ */
+static int posix_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
{
- if ( caller_fl->fl_owner == sys_fl->fl_owner
- && caller_fl->fl_fd == sys_fl->fl_fd)
- return 0;
- if (!overlap(caller_fl, sys_fl))
- return 0;
+ /* POSIX locks owned by the same process do not conflict with
+ * each other.
+ */
+ if ((sys_fl->fl_flags == F_POSIX) &&
+ (caller_fl->fl_owner == sys_fl->fl_owner))
+ return (0);
+
+ return (locks_conflict(caller_fl, sys_fl));
+}
+
+/* Determine if lock sys_fl blocks lock caller_fl. FLOCK specific checking
+ * before calling the locks_conflict().
+ */
+static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
+{
+ /* FLOCK locks referring to the same filp do not conflict with
+ * each other.
+ */
+ if ((sys_fl->fl_flags == F_FLOCK) &&
+ (caller_fl->fl_file == sys_fl->fl_file))
+ return (0);
+
+ return (locks_conflict(caller_fl, sys_fl));
+}
+
+/* Determine if lock sys_fl blocks lock caller_fl. Common functionality
+ * checks for overlapping locks and shared/exclusive status.
+ */
+static int locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
+{
+ if (!locks_overlap(caller_fl, sys_fl))
+ return (0);
+
switch (caller_fl->fl_type) {
case F_RDLCK :
- return sys_fl->fl_type != F_RDLCK;
+ return (sys_fl->fl_type == F_WRLCK);
+
case F_WRLCK :
- return 1; /* overlapping region not owned by caller */
+ return (1);
+
+ default:
+ printk("locks_conflict(): impossible lock type - %d\n",
+ caller_fl->fl_type);
+ break;
}
- return 0; /* shouldn't get here, but just in case */
+ return (0); /* This should never happen */
}
-static int overlap(struct file_lock *fl1, struct file_lock *fl2)
+/* Check if two locks overlap each other.
+ */
+static int locks_overlap(struct file_lock *fl1, struct file_lock *fl2)
{
- return fl1->fl_end >= fl2->fl_start && fl2->fl_end >= fl1->fl_start;
+ return ((fl1->fl_end >= fl2->fl_start) &&
+ (fl2->fl_end >= fl1->fl_start));
}
-/*
- * Add a lock to a file ...
- * Result is 0 for success or -ENOLCK.
- *
- * We merge adjacent locks whenever possible.
- *
- * WARNING: We assume the lock doesn't conflict with any other lock.
+/* This function tests for deadlock condition before putting a process to sleep.
+ * The detection scheme is recursive... we may need a test to make it exit if the
+ * function gets stuck due to bad lock data. 4.4 BSD uses a maximum depth of 50
+ * for this.
*/
-
-/*
- * Rewritten by Kai Petzke:
- * We sort the lock list first by owner, then by the starting address.
+static int posix_locks_deadlock(struct task_struct *my_task,
+ struct task_struct *blocked_task)
+{
+ struct wait_queue *dlock_wait;
+ struct file_lock *fl;
+
+ for (fl = file_lock_table; fl != NULL; fl = fl->fl_nextlink) {
+ if (fl->fl_owner == NULL)
+ continue; /* Should never happen! */
+ if (fl->fl_owner != my_task)
+ continue;
+ if (fl->fl_wait == NULL)
+ continue; /* no queues */
+ dlock_wait = fl->fl_wait;
+ do {
+ if (dlock_wait->task != NULL) {
+ if (dlock_wait->task == blocked_task)
+ return (-EDEADLOCK);
+ if (posix_locks_deadlock(dlock_wait->task, blocked_task))
+ return (-EDEADLOCK);
+ }
+ dlock_wait = dlock_wait->next;
+ } while (dlock_wait != fl->fl_wait);
+ }
+ return (0);
+}
+
+/* Try to create a FLOCK lock on filp. We rely on FLOCK locks being sorting
+ * first in an inode's lock list, and always insert new locks at the head
+ * of the list.
+ */
+static int flock_lock_file(struct file *filp, struct file_lock *caller,
+ unsigned int wait)
+{
+ struct file_lock *fl;
+ struct file_lock *new_fl;
+ struct file_lock **before;
+ int change = 0;
+
+ /* This a compact little algorithm based on us always placing FLOCK
+ * locks at the front of the list.
+ */
+ before = &filp->f_inode->i_flock;
+ while ((fl = *before) && (fl->fl_flags == F_FLOCK)) {
+ if (caller->fl_file == fl->fl_file) {
+ if (caller->fl_type == fl->fl_type)
+ return (0);
+ change = 1;
+ break;
+ }
+ before = &fl->fl_next;
+ }
+ /* change means that we are changing the type of an existing lock, or
+ * or else unlocking it.
+ */
+ if (change)
+ locks_delete_lock(before, caller->fl_type != F_UNLCK);
+ if (caller->fl_type == F_UNLCK)
+ return (0);
+ if ((new_fl = locks_alloc_lock(caller)) == NULL)
+ return (-ENOLCK);
+ repeat:
+ for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
+ if (!flock_locks_conflict(new_fl, fl))
+ continue;
+
+ if (wait) {
+ if (current->signal & ~current->blocked) {
+ locks_delete_lock(&new_fl, 0);
+ return (-ERESTARTSYS);
+ }
+ locks_insert_block(&fl->fl_block, new_fl);
+ interruptible_sleep_on(&new_fl->fl_wait);
+ wake_up(&new_fl->fl_wait);
+ if (current->signal & ~current->blocked) {
+ locks_delete_lock(&new_fl, 0);
+ return (-ERESTARTSYS);
+ }
+ goto repeat;
+ }
+ locks_delete_lock(&new_fl, 0);
+ return (-EAGAIN);
+ }
+ locks_insert_lock(&filp->f_inode->i_flock, new_fl);
+ return (0);
+}
+
+/* Add a POSIX style lock to a file.
+ * We merge adjacent locks whenever possible. POSIX locks come after FLOCK
+ * locks in the list and are sorted by owner task, then by starting address
*
+ * Kai Petzke writes:
* To make freeing a lock much faster, we keep a pointer to the lock before the
* actual one. But the real gain of the new coding was, that lock_it() and
* unlock_it() became one function.
@@ -293,46 +478,62 @@ static int overlap(struct file_lock *fl1, struct file_lock *fl2)
* To all purists: Yes, I use a few goto's. Just pass on to the next function.
*/
-static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd)
+static int posix_lock_file(struct file *filp, struct file_lock *caller,
+ unsigned int wait)
{
struct file_lock *fl;
- struct file_lock *left = 0;
- struct file_lock *right = 0;
+ struct file_lock *new_fl;
+ struct file_lock *left = NULL;
+ struct file_lock *right = NULL;
struct file_lock **before;
int added = 0;
+ if (caller->fl_type != F_UNLCK) {
+repeat:
+ for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
+ if (!posix_locks_conflict(caller, fl))
+ continue;
+ if (wait) {
+ if (current->signal & ~current->blocked)
+ return (-ERESTARTSYS);
+ if (fl->fl_flags == F_POSIX)
+ if (posix_locks_deadlock(caller->fl_owner, fl->fl_owner))
+ return (-EDEADLOCK);
+ interruptible_sleep_on(&fl->fl_wait);
+ if (current->signal & ~current->blocked)
+ return (-ERESTARTSYS);
+ goto repeat;
+ }
+ return (-EAGAIN);
+ }
+ }
/*
* Find the first old lock with the same owner as the new lock.
*/
-
+
before = &filp->f_inode->i_flock;
- while ((fl = *before) &&
- (caller->fl_owner != fl->fl_owner ||
- caller->fl_fd != fl->fl_fd))
- before = &fl->fl_next;
- /*
- * Look up all locks of this owner.
+ /* First skip FLOCK locks and locks owned by other processes.
*/
+ while ((fl = *before) && ((fl->fl_flags == F_FLOCK) ||
+ (caller->fl_owner != fl->fl_owner)))
+ before = &fl->fl_next;
- while ( (fl = *before)
- && caller->fl_owner == fl->fl_owner
- && caller->fl_fd == fl->fl_fd) {
- /*
- * Detect adjacent or overlapping regions (if same lock type)
+ /* Process locks with this owner.
+ */
+ while ((fl = *before) && (caller->fl_owner == fl->fl_owner)) {
+ /* Detect adjacent or overlapping regions (if same lock type)
*/
if (caller->fl_type == fl->fl_type) {
if (fl->fl_end < caller->fl_start - 1)
goto next_lock;
- /*
- * If the next lock in the list has entirely bigger
+ /* If the next lock in the list has entirely bigger
* addresses than the new one, insert the lock here.
*/
if (fl->fl_start > caller->fl_end + 1)
break;
- /*
- * If we come here, the new and old lock are of the
+ /* If we come here, the new and old lock are of the
* same type and adjacent or overlapping. Make one
* lock yielding from the lower start address of both
* locks to the higher end address.
@@ -346,15 +547,14 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd)
else
caller->fl_end = fl->fl_end;
if (added) {
- free_lock(before);
+ locks_delete_lock(before, 0);
continue;
}
caller = fl;
added = 1;
goto next_lock;
}
- /*
- * Processing for different lock types is a bit more complex.
+ /* Processing for different lock types is a bit more complex.
*/
if (fl->fl_end < caller->fl_start)
goto next_lock;
@@ -364,8 +564,7 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd)
added = 1;
if (fl->fl_start < caller->fl_start)
left = fl;
- /*
- * If the next lock in the list has a higher end address than
+ /* If the next lock in the list has a higher end address than
* the new one, insert the new one here.
*/
if (fl->fl_end > caller->fl_end) {
@@ -373,134 +572,162 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd)
break;
}
if (fl->fl_start >= caller->fl_start) {
- /*
- * The new lock completely replaces an old one (This may
+ /* The new lock completely replaces an old one (This may
* happen several times).
*/
if (added) {
- free_lock(before);
+ locks_delete_lock(before, 0);
continue;
}
- /*
- * Replace the old lock with the new one. Wake up
+ /* Replace the old lock with the new one. Wake up
* anybody waiting for the old one, as the change in
* lock type might satisfy his needs.
*/
wake_up(&fl->fl_wait);
fl->fl_start = caller->fl_start;
- fl->fl_end = caller->fl_end;
- fl->fl_type = caller->fl_type;
+ fl->fl_end = caller->fl_end;
+ fl->fl_type = caller->fl_type;
caller = fl;
added = 1;
}
- /*
- * Go on to next lock.
+ /* Go on to next lock.
*/
-next_lock:
+ next_lock:
before = &(*before)->fl_next;
}
- if (! added) {
- if (caller->fl_type == F_UNLCK) {
-/*
- * XXX - under iBCS-2, attempting to unlock a not-locked region is
- * not considered an error condition, although I'm not sure if this
- * should be a default behavior (it makes porting to native Linux easy)
- * or a personality option.
- *
- * Does Xopen/1170 say anything about this?
- * - drew@Colorado.EDU
- */
-#if 0
- return -EINVAL;
-#else
- return 0;
-#endif
- }
- if (! (caller = alloc_lock(before, caller, fd)))
- return -ENOLCK;
+ if (!added) {
+ if (caller->fl_type == F_UNLCK)
+ return (0);
+ if ((new_fl = locks_alloc_lock(caller)) == NULL)
+ return (-ENOLCK);
+ locks_insert_lock(before, new_fl);
+
}
if (right) {
if (left == right) {
- /*
- * The new lock breaks the old one in two pieces, so we
+ /* The new lock breaks the old one in two pieces, so we
* have to allocate one more lock (in this case, even
* F_UNLCK may fail!).
*/
- if (! (left = alloc_lock(before, right, fd))) {
- if (! added)
- free_lock(before);
- return -ENOLCK;
+ if ((left = locks_alloc_lock(right)) == NULL) {
+ if (!added)
+ locks_delete_lock(before, 0);
+ return (-ENOLCK);
}
+ locks_insert_lock(before, left);
}
right->fl_start = caller->fl_end + 1;
}
if (left)
left->fl_end = caller->fl_start - 1;
- return 0;
+ return (0);
}
-/*
- * File_lock() inserts a lock at the position pos of the linked list.
- *
- * Modified to create a new node if no free entries available - Chad Page
- *
+/* Allocate memory for a new lock and initialize its fields from
+ * fl. The lock is not inserted into any lists until locks_insert_lock()
+ * or locks_insert_block() are called.
*/
-static struct file_lock *alloc_lock(struct file_lock **pos,
- struct file_lock *fl,
- unsigned int fd)
+static struct file_lock *locks_alloc_lock(struct file_lock *fl)
{
struct file_lock *tmp;
- tmp = file_lock_free_list;
-
- if (tmp == NULL)
- {
- /* Okay, let's make a new file_lock structure... */
- tmp = (struct file_lock *)kmalloc(sizeof(struct file_lock), GFP_KERNEL);
- tmp -> fl_owner = NULL;
- tmp -> fl_next = file_lock_free_list;
- tmp -> fl_nextlink = file_lock_table;
- file_lock_table = tmp;
- }
- else
- {
- /* remove from free list */
- file_lock_free_list = tmp->fl_next;
- }
-
- if (tmp->fl_owner != NULL)
- panic("alloc_lock: broken free list\n");
+ /* Okay, let's make a new file_lock structure... */
+ if ((tmp = (struct file_lock *)kmalloc(sizeof(struct file_lock),
+ GFP_KERNEL)) == NULL)
+ return (tmp);
+
+ tmp->fl_nextlink = NULL;
+ tmp->fl_prevlink = NULL;
+ tmp->fl_next = NULL;
+ tmp->fl_block = NULL;
+ tmp->fl_flags = fl->fl_flags;
+ tmp->fl_owner = fl->fl_owner;
+ tmp->fl_file = fl->fl_file;
+ tmp->fl_wait = NULL;
+ tmp->fl_type = fl->fl_type;
+ tmp->fl_start = fl->fl_start;
+ tmp->fl_end = fl->fl_end;
- *tmp = *fl;
+ return (tmp);
+}
- tmp->fl_next = *pos; /* insert into file's list */
- *pos = tmp;
+/* Insert file lock fl into an inode's lock list at the position indicated
+ * by pos. At the same time add the lock to the global file lock list.
+ */
- tmp->fl_owner = current; /* FIXME: needed? */
- tmp->fl_fd = fd; /* FIXME: needed? */
- tmp->fl_wait = NULL;
- return tmp;
+static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
+{
+ fl->fl_nextlink = file_lock_table;
+ fl->fl_prevlink = NULL;
+ if (file_lock_table != NULL)
+ file_lock_table->fl_prevlink = fl;
+ file_lock_table = fl;
+ fl->fl_next = *pos; /* insert into file's list */
+ *pos = fl;
+
+ return;
}
-/*
- * Add a lock to the free list ...
+/* Delete a lock and free it.
+ * First remove our lock from the lock lists. Then remove all the blocked locks
+ * from our blocked list, waking up the processes that own them. If told to wait,
+ * then sleep on each of these lock's wait queues. Each blocked process will wake
+ * up and immediately wake up its own wait queue allowing us to be scheduled again.
+ * Lastly, wake up our own wait queue before freeing the file_lock structure.
*/
-static void free_lock(struct file_lock **fl_p)
+static void locks_delete_lock(struct file_lock **fl_p, unsigned int wait)
{
struct file_lock *fl;
-
+ struct file_lock *bfl;
+
fl = *fl_p;
- if (fl->fl_owner == NULL) /* sanity check */
- panic("free_lock: broken lock list\n");
-
*fl_p = (*fl_p)->fl_next;
- fl->fl_next = file_lock_free_list; /* add to free list */
- file_lock_free_list = fl;
- fl->fl_owner = NULL; /* for sanity checks */
+ if (fl->fl_nextlink != NULL)
+ fl->fl_nextlink->fl_prevlink = fl->fl_prevlink;
+
+ if (fl->fl_prevlink != NULL)
+ fl->fl_prevlink->fl_nextlink = fl->fl_nextlink;
+ else
+ file_lock_table = fl->fl_nextlink;
+
+ while ((bfl = fl->fl_block) != NULL) {
+ fl->fl_block = bfl->fl_block;
+ bfl->fl_block = NULL;
+ wake_up(&bfl->fl_wait);
+ if (wait)
+ sleep_on(&bfl->fl_wait);
+ }
wake_up(&fl->fl_wait);
+ kfree(fl);
+
+ return;
+}
+
+/* Add lock fl to the blocked list pointed to by block.
+ * We search to the end of the existing list and insert the the new
+ * struct. This ensures processes will be woken up in the order they
+ * blocked.
+ * NOTE: nowhere does the documentation insist that processes be woken
+ * up in this order, but it seems like the reasonable thing to do.
+ * If the blocked list gets long then this search could get expensive,
+ * in which case we could consider waking the processes up in reverse
+ * order, or making the blocked list a doubly linked circular list.
+ */
+static void locks_insert_block(struct file_lock **block, struct file_lock *fl)
+{
+ struct file_lock *bfl;
+
+ while ((bfl = *block) != NULL)
+ block = &bfl->fl_block;
+
+ *block = fl;
+ fl->fl_block = NULL;
+
+ return;
}
+
diff --git a/fs/minix/Makefile b/fs/minix/Makefile
index 20e7f3dae..82250ca47 100644
--- a/fs/minix/Makefile
+++ b/fs/minix/Makefile
@@ -23,6 +23,8 @@ minix.o: $(OBJS)
dep:
$(CPP) -M *.c > .depend
+modules: minix.o
+
#
# include a dependency file if one exists
#
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 64fe09f87..ac97cb84e 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -6,6 +6,10 @@
/* bitmap.c contains the code that handles the inode and block bitmaps */
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/stat.h>
@@ -88,7 +92,7 @@ repeat:
j = 8192;
for (i=0 ; i<8 ; i++)
if ((bh=sb->u.minix_sb.s_zmap[i]) != NULL)
- if ((j=find_first_zero_bit(bh->b_data,8192)) < 8192)
+ if ((j=find_first_zero_bit(bh->b_data, 8192)) < 8192)
break;
if (i>=8 || !bh || j>=8192)
return 0;
@@ -171,7 +175,7 @@ struct inode * minix_new_inode(const struct inode * dir)
j = 8192;
for (i=0 ; i<8 ; i++)
if ((bh = inode->i_sb->u.minix_sb.s_imap[i]) != NULL)
- if ((j=find_first_zero_bit(bh->b_data,8192)) < 8192)
+ if ((j=find_first_zero_bit(bh->b_data, 8192)) < 8192)
break;
if (!bh || j >= 8192) {
iput(inode);
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 6ece61971..dccc10469 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -6,22 +6,24 @@
* minix directory handling functions
*/
-#include <asm/segment.h>
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+#include <linux/string.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/minix_fs.h>
#include <linux/stat.h>
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+3) & ~3)
+#include <asm/segment.h>
static int minix_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
{
return -EISDIR;
}
-static int minix_readdir(struct inode *, struct file *, struct dirent *, int);
+static int minix_readdir(struct inode *, struct file *, void *, filldir_t);
static struct file_operations minix_dir_operations = {
NULL, /* lseek - default */
@@ -58,11 +60,9 @@ struct inode_operations minix_dir_inode_operations = {
};
static int minix_readdir(struct inode * inode, struct file * filp,
- struct dirent * dirent, int count)
+ void * dirent, filldir_t filldir)
{
- unsigned int offset,i,ret;
- int version;
- char c;
+ unsigned int offset;
struct buffer_head * bh;
struct minix_dir_entry * de;
struct minix_sb_info * info;
@@ -72,37 +72,26 @@ static int minix_readdir(struct inode * inode, struct file * filp,
info = &inode->i_sb->u.minix_sb;
if (filp->f_pos & (info->s_dirsize - 1))
return -EBADF;
- ret = 0;
- while (!ret && filp->f_pos < inode->i_size) {
+ while (filp->f_pos < inode->i_size) {
offset = filp->f_pos & 1023;
bh = minix_bread(inode,(filp->f_pos)>>BLOCK_SIZE_BITS,0);
if (!bh) {
filp->f_pos += 1024-offset;
continue;
}
- while (!ret && offset < 1024 && filp->f_pos < inode->i_size) {
+ do {
de = (struct minix_dir_entry *) (offset + bh->b_data);
- offset += info->s_dirsize;
- filp->f_pos += info->s_dirsize;
-retry:
if (de->inode) {
- version = inode->i_version;
- for (i = 0; i < info->s_namelen; i++)
- if ((c = de->name[i]) != 0)
- put_fs_byte(c,i+dirent->d_name);
- else
- break;
- if (i) {
- put_fs_long(de->inode,&dirent->d_ino);
- put_fs_byte(0,i+dirent->d_name);
- put_fs_word(i,&dirent->d_reclen);
- if (version != inode->i_version)
- goto retry;
- ret = ROUND_UP(NAME_OFFSET(dirent)+i+1);
+ int size = strnlen(de->name, info->s_namelen);
+ if (filldir(dirent, de->name, size, filp->f_pos, de->inode) < 0) {
+ brelse(bh);
+ return 0;
}
}
- }
+ offset += info->s_dirsize;
+ filp->f_pos += info->s_dirsize;
+ } while (offset < 1024 && filp->f_pos < inode->i_size);
brelse(bh);
}
- return ret;
+ return 0;
}
diff --git a/fs/minix/file.c b/fs/minix/file.c
index 670fb5e75..db3097c37 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -6,6 +6,10 @@
* minix regular file handling primitives
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <asm/system.h>
diff --git a/fs/minix/fsync.c b/fs/minix/fsync.c
index 737a5bfcd..436d27191 100644
--- a/fs/minix/fsync.c
+++ b/fs/minix/fsync.c
@@ -8,6 +8,10 @@
* minix fsync primitive
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <asm/system.h>
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 2aeb538ee..595485a35 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -4,6 +4,14 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
@@ -63,6 +71,7 @@ void minix_put_super(struct super_block *sb)
brelse(sb->u.minix_sb.s_zmap[i]);
brelse (sb->u.minix_sb.s_sbh);
unlock_super(sb);
+ MOD_DEC_USE_COUNT;
return;
}
@@ -121,12 +130,14 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
if (32 != sizeof (struct minix_inode))
panic("bad i-node size");
+ MOD_INC_USE_COUNT;
lock_super(s);
set_blocksize(dev, BLOCK_SIZE);
if (!(bh = bread(dev,1,BLOCK_SIZE))) {
s->s_dev=0;
unlock_super(s);
printk("MINIX-fs: unable to read superblock\n");
+ MOD_DEC_USE_COUNT;
return NULL;
}
ms = (struct minix_super_block *) bh->b_data;
@@ -155,6 +166,7 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
brelse(bh);
if (!silent)
printk("VFS: Can't find a minix filesystem on dev 0x%04x.\n", dev);
+ MOD_DEC_USE_COUNT;
return NULL;
}
for (i=0;i < MINIX_I_MAP_SLOTS;i++)
@@ -181,6 +193,7 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
unlock_super(s);
brelse(bh);
printk("MINIX-fs: bad superblock or unable to read bitmaps\n");
+ MOD_DEC_USE_COUNT;
return NULL;
}
set_bit(0,s->u.minix_sb.s_imap[0]->b_data);
@@ -194,6 +207,7 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
s->s_dev = 0;
brelse(bh);
printk("MINIX-fs: get root inode failed\n");
+ MOD_DEC_USE_COUNT;
return NULL;
}
if (!(s->s_flags & MS_RDONLY)) {
@@ -210,22 +224,19 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
return s;
}
-void minix_statfs(struct super_block *sb, struct statfs *buf)
+void minix_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
- long tmp;
-
- put_fs_long(MINIX_SUPER_MAGIC, &buf->f_type);
- put_fs_long(1024, &buf->f_bsize);
- tmp = sb->u.minix_sb.s_nzones - sb->u.minix_sb.s_firstdatazone;
- tmp <<= sb->u.minix_sb.s_log_zone_size;
- put_fs_long(tmp, &buf->f_blocks);
- tmp = minix_count_free_blocks(sb);
- put_fs_long(tmp, &buf->f_bfree);
- put_fs_long(tmp, &buf->f_bavail);
- put_fs_long(sb->u.minix_sb.s_ninodes, &buf->f_files);
- put_fs_long(minix_count_free_inodes(sb), &buf->f_ffree);
- put_fs_long(sb->u.minix_sb.s_namelen, &buf->f_namelen);
- /* Don't know what value to put in buf->f_fsid */
+ struct statfs tmp;
+
+ tmp.f_type = MINIX_SUPER_MAGIC;
+ tmp.f_bsize = 1024;
+ tmp.f_blocks = (sb->u.minix_sb.s_nzones - sb->u.minix_sb.s_firstdatazone) << sb->u.minix_sb.s_log_zone_size;
+ tmp.f_bfree = minix_count_free_blocks(sb);
+ tmp.f_bavail = tmp.f_bavail;
+ tmp.f_files = sb->u.minix_sb.s_ninodes;
+ tmp.f_ffree = minix_count_free_inodes(sb);
+ tmp.f_namelen = sb->u.minix_sb.s_namelen;
+ memcpy_tofs(buf, &tmp, bufsiz);
}
#define inode_bmap(inode,nr) ((inode)->u.minix_i.i_data[(nr)])
@@ -511,3 +522,25 @@ int minix_sync_inode(struct inode * inode)
brelse (bh);
return err;
}
+
+#ifdef MODULE
+
+char kernel_version[] = UTS_RELEASE;
+
+static struct file_system_type minix_fs_type = {
+ minix_read_super, "minix", 1, NULL
+};
+
+int init_module(void)
+{
+ register_filesystem(&minix_fs_type);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unregister_filesystem(&minix_fs_type);
+}
+
+#endif
+
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index dd60e4602..995008c92 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -4,6 +4,10 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
@@ -23,11 +27,11 @@
static inline int namecompare(int len, int maxlen,
const char * name, const char * buffer)
{
- if (len >= maxlen)
+ if (len > maxlen)
return 0;
if (len < maxlen && buffer[len])
return 0;
- return !memcmp(name,buffer,len);
+ return !memcmp(name, buffer, len);
}
/*
@@ -189,6 +193,7 @@ static int minix_add_entry(struct inode * dir,
}
} else {
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->i_dirt = 1;
for (i = 0; i < info->s_namelen ; i++)
de->name[i] = (i < namelen) ? name[i] : 0;
dir->i_version = ++event;
diff --git a/fs/minix/symlink.c b/fs/minix/symlink.c
index bbd2b1f56..86dabf936 100644
--- a/fs/minix/symlink.c
+++ b/fs/minix/symlink.c
@@ -6,6 +6,10 @@
* minix symlink handling code
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/errno.h>
diff --git a/fs/minix/truncate.c b/fs/minix/truncate.c
index 0b127b9b8..503c7caab 100644
--- a/fs/minix/truncate.c
+++ b/fs/minix/truncate.c
@@ -4,6 +4,10 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
diff --git a/fs/msdos/Makefile b/fs/msdos/Makefile
index 2c690d3ea..af5769dac 100644
--- a/fs/msdos/Makefile
+++ b/fs/msdos/Makefile
@@ -7,10 +7,6 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-ifndef CONFIG_MSDOS_FS
-CFLAGS := $(CFLAGS) -DMODULE
-endif
-
.c.s:
$(CC) $(CFLAGS) -S $<
.c.o:
@@ -18,11 +14,14 @@ endif
.s.o:
$(AS) -o $*.o $<
-OBJS= namei.o inode.o file.o dir.o misc.o fat.o
+OBJS= buffer.o namei.o inode.o file.o dir.o misc.o fat.o mmap.o
msdos.o: $(OBJS)
$(LD) -r -o msdos.o $(OBJS)
+modules: msdos.o
+ ln -sf ../fs/msdos/msdos.o $(TOPDIR)/modules
+
dep:
$(CPP) -M *.c > .depend
diff --git a/fs/msdos/buffer.c b/fs/msdos/buffer.c
new file mode 100644
index 000000000..13e7aaeb6
--- /dev/null
+++ b/fs/msdos/buffer.c
@@ -0,0 +1,148 @@
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/msdos_fs.h>
+
+struct buffer_head *msdos_bread (
+ struct super_block *sb,
+ int block)
+{
+ struct buffer_head *ret = NULL;
+ if (sb->s_blocksize == 512){
+ ret = bread (sb->s_dev,block,512);
+ }else{
+ struct buffer_head *real = bread (sb->s_dev,block>>1,1024);
+ if (real != NULL){
+ ret = (struct buffer_head *)kmalloc (sizeof(struct buffer_head)
+ ,GFP_KERNEL);
+ if (ret != NULL){
+ /* #Specification: msdos / strategy / special device / dummy blocks
+ Many special device (Scsi optical disk for one) use
+ larger hardware sector size. This allows for higher
+ capacity.
+
+ Most of the time, the MsDOS file system that sit
+ on this device is totally unaligned. It use logically
+ 512 bytes sector size, with logical sector starting
+ in the middle of a hardware block. The bad news is
+ that a hardware sector may hold data own by two
+ different files. This means that the hardware sector
+ must be read, patch and written almost all the time.
+
+ Needless to say that it kills write performance
+ on all OS.
+
+ Internally the linux msdos fs is using 512 bytes
+ logical sector. When accessing such a device, we
+ allocate dummy buffer cache blocks, that we stuff
+ with the information of a real one (1k large).
+
+ This strategy is used to hide this difference to
+ the core of the msdos fs. The slowdown is not
+ hidden though!
+ */
+ /*
+ The memset is there only to catch errors. The msdos
+ fs is only using b_data
+ */
+ memset (ret,0,sizeof(*ret));
+ ret->b_data = real->b_data;
+ if (block & 1) ret->b_data += 512;
+ ret->b_next = real;
+ }else{
+ brelse (real);
+ }
+ }
+ }
+ return ret;
+}
+struct buffer_head *msdos_getblk (
+ struct super_block *sb,
+ int block)
+{
+ struct buffer_head *ret = NULL;
+ if (sb->s_blocksize == 512){
+ ret = getblk (sb->s_dev,block,512);
+ }else{
+ /* #Specification: msdos / special device / writing
+ A write is always preceded by a read of the complete block
+ (large hardware sector size). This defeat write performance.
+ There is a possibility to optimize this when writing large
+ chunk by making sure we are filling large block. Volunteer ?
+ */
+ ret = msdos_bread (sb,block);
+ }
+ return ret;
+}
+
+void msdos_brelse (
+ struct super_block *sb,
+ struct buffer_head *bh)
+{
+ if (bh != NULL){
+ if (sb->s_blocksize == 512){
+ brelse (bh);
+ }else{
+ brelse (bh->b_next);
+ /* We can free the dummy because a new one is allocated at
+ each msdos_getblk() and msdos_bread().
+ */
+ kfree (bh);
+ }
+ }
+}
+
+void msdos_mark_buffer_dirty (
+ struct super_block *sb,
+ struct buffer_head *bh,
+ int dirty_val)
+{
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+ mark_buffer_dirty (bh,dirty_val);
+}
+
+void msdos_set_uptodate (
+ struct super_block *sb,
+ struct buffer_head *bh,
+ int val)
+{
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+ bh->b_uptodate = val;
+}
+int msdos_is_uptodate (
+ struct super_block *sb,
+ struct buffer_head *bh)
+{
+ if (sb->s_blocksize != 512){
+ bh = bh->b_next;
+ }
+ return bh->b_uptodate;
+}
+
+void msdos_ll_rw_block (
+ struct super_block *sb,
+ int opr,
+ int nbreq,
+ struct buffer_head *bh[32])
+{
+ if (sb->s_blocksize == 512){
+ ll_rw_block(opr,nbreq,bh);
+ }else{
+ struct buffer_head *tmp[32];
+ int i;
+ for (i=0; i<nbreq; i++){
+ tmp[i] = bh[i]->b_next;
+ }
+ ll_rw_block(opr,nbreq,tmp);
+ }
+}
+
diff --git a/fs/msdos/dir.c b/fs/msdos/dir.c
index 2138b8778..7fd17483e 100644
--- a/fs/msdos/dir.c
+++ b/fs/msdos/dir.c
@@ -6,6 +6,10 @@
* MS-DOS directory handling functions
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/fs.h>
@@ -14,8 +18,7 @@
#include <linux/stat.h>
#include <linux/string.h>
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+3) & ~3)
+#include "msbuffer.h"
#define PRINTK(X)
@@ -59,33 +62,35 @@ struct inode_operations msdos_dir_inode_operations = {
int msdos_readdir(
struct inode *inode,
struct file *filp,
- struct dirent *dirent, /* dirent in user space */
- int count)
+ void *dirent,
+ filldir_t filldir)
{
+ struct super_block *sb = inode->i_sb;
int ino,i,i2,last;
- char c,*walk;
+ char c;
struct buffer_head *bh;
struct msdos_dir_entry *de;
+ unsigned long oldpos = filp->f_pos;
- if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF;
- if (inode->i_ino == MSDOS_ROOT_INO) {
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -EBADF;
/* Fake . and .. for the root directory. */
- if (filp->f_pos == 2) filp->f_pos = 0;
- else if (filp->f_pos < 2) {
- walk = filp->f_pos++ ? ".." : ".";
- for (i = 0; *walk; walk++)
- put_fs_byte(*walk,dirent->d_name+i++);
- put_fs_long(MSDOS_ROOT_INO,&dirent->d_ino);
- put_fs_byte(0,dirent->d_name+i);
- put_fs_word(i,&dirent->d_reclen);
- return ROUND_UP(NAME_OFFSET(dirent) + i + 1);
+ if (inode->i_ino == MSDOS_ROOT_INO) {
+ while (oldpos < 2) {
+ if (filldir(dirent, "..", oldpos+1, oldpos, MSDOS_ROOT_INO) < 0)
+ return 0;
+ oldpos++;
+ filp->f_pos++;
}
+ if (oldpos == 2)
+ filp->f_pos = 0;
}
- if (filp->f_pos & (sizeof(struct msdos_dir_entry)-1)) return -ENOENT;
+ if (filp->f_pos & (sizeof(struct msdos_dir_entry)-1))
+ return -ENOENT;
bh = NULL;
while ((ino = msdos_get_entry(inode,&filp->f_pos,&bh,&de)) > -1) {
if (!IS_FREE(de->name) && !(de->attr & ATTR_VOLUME)) {
- char bufname[13];
+ char bufname[12];
char *ptname = bufname;
for (i = last = 0; i < 8; i++) {
if (!(c = de->name[i])) break;
@@ -103,23 +108,20 @@ int msdos_readdir(
if (c != ' ')
last = i+1;
ptname[i] = c;
- i++;
+ i++;
}
if ((i = last) != 0) {
if (!strcmp(de->name,MSDOS_DOT))
ino = inode->i_ino;
else if (!strcmp(de->name,MSDOS_DOTDOT))
- ino = msdos_parent_ino(inode,0);
- bufname[i] = '\0';
- put_fs_long(ino,&dirent->d_ino);
- memcpy_tofs(dirent->d_name,bufname,i+1);
- put_fs_word(i,&dirent->d_reclen);
- PRINTK (("readdir avant brelse\n"));
- brelse(bh);
- PRINTK (("readdir retourne %d\n",i));
- return ROUND_UP(NAME_OFFSET(dirent) + i + 1);
+ ino = msdos_parent_ino(inode,0);
+ if (filldir(dirent, bufname, i, oldpos, ino) < 0) {
+ filp->f_pos = oldpos;
+ break;
+ }
}
}
+ oldpos = filp->f_pos;
}
if (bh) brelse(bh);
return 0;
diff --git a/fs/msdos/fat.c b/fs/msdos/fat.c
index 651e58b24..6059ec7bc 100644
--- a/fs/msdos/fat.c
+++ b/fs/msdos/fat.c
@@ -4,12 +4,17 @@
* Written 1992,1993 by Werner Almesberger
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/msdos_fs.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
+#include "msbuffer.h"
static struct fat_cache *fat_cache,cache[FAT_CACHE];
@@ -28,16 +33,16 @@ int fat_access(struct super_block *sb,int nr,int new_value)
first = nr*3/2;
last = first+1;
}
- if (!(bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
- SECTOR_BITS)))) {
+ if (!(bh = bread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
+ SECTOR_BITS),SECTOR_SIZE))) {
printk("bread in fat_access failed\n");
return 0;
}
if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS))
bh2 = bh;
else {
- if (!(bh2 = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last
- >> SECTOR_BITS)))) {
+ if (!(bh2 = bread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last
+ >> SECTOR_BITS),SECTOR_SIZE))) {
brelse(bh);
printk("bread in fat_access failed\n");
return 0;
@@ -74,16 +79,16 @@ int fat_access(struct super_block *sb,int nr,int new_value)
}
mark_buffer_dirty(bh, 1);
for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) {
- if (!(c_bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->
+ if (!(c_bh = bread(sb->s_dev,MSDOS_SB(sb)->
fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)->
- fat_length*copy))) break;
+ fat_length*copy,SECTOR_SIZE))) break;
memcpy(c_bh->b_data,bh->b_data,SECTOR_SIZE);
mark_buffer_dirty(c_bh, 1);
if (bh != bh2) {
- if (!(c_bh2 = msdos_sread(sb->s_dev,
+ if (!(c_bh2 = bread(sb->s_dev,
MSDOS_SB(sb)->fat_start+(first >>
SECTOR_BITS)+MSDOS_SB(sb)->fat_length*copy
- +1))) {
+ +1,SECTOR_SIZE))) {
brelse(c_bh);
break;
}
diff --git a/fs/msdos/file.c b/fs/msdos/file.c
index fb41fff21..491084a71 100644
--- a/fs/msdos/file.c
+++ b/fs/msdos/file.c
@@ -6,6 +6,10 @@
* MS-DOS regular file handling primitives
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <asm/system.h>
@@ -18,6 +22,8 @@
#include <linux/stat.h>
#include <linux/string.h>
+#include "msbuffer.h"
+
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
@@ -55,6 +61,52 @@ struct inode_operations msdos_file_inode_operations = {
NULL, /* permission */
NULL /* smap */
};
+/* #Specification: msdos / special devices / mmap
+ Mmapping does work because a special mmap is provide in that case.
+ Note that it is much less efficient than the generic_mmap normally
+ used since it allocate extra buffer. generic_mmap is used for
+ normal device (512 bytes hardware sectors).
+*/
+static struct file_operations msdos_file_operations_1024 = {
+ NULL, /* lseek - default */
+ msdos_file_read, /* read */
+ msdos_file_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ msdos_mmap, /* mmap */
+ NULL, /* no special open is needed */
+ NULL, /* release */
+ file_fsync /* fsync */
+};
+
+/* #Specification: msdos / special devices / swap file
+ Swap file can't work on special devices with a large sector
+ size (1024 bytes hard sector). Those devices have a weird
+ MsDOS filesystem layout. Generally a single hardware sector
+ may contain 2 unrelated logical sector. This mean that there is
+ no easy way to do a mapping between disk sector of a file and virtual
+ memory. So swap file is difficult (not available right now)
+ on those devices. Off course, Ext2 does not have this problem.
+*/
+struct inode_operations msdos_file_inode_operations_1024 = {
+ &msdos_file_operations_1024, /* default file operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ msdos_truncate, /* truncate */
+ NULL, /* permission */
+ NULL /* smap */
+};
#define MSDOS_PREFETCH 32
struct msdos_pre {
@@ -72,6 +124,7 @@ static void msdos_prefetch (
struct msdos_pre *pre,
int nb) /* How many must be prefetch at once */
{
+ struct super_block *sb = inode->i_sb;
struct buffer_head *bhreq[MSDOS_PREFETCH]; /* Buffers not */
/* already read */
int nbreq=0; /* Number of buffers in bhreq */
@@ -85,12 +138,12 @@ static void msdos_prefetch (
bh = getblk(inode->i_dev,sector,SECTOR_SIZE);
if (bh == NULL) break;
pre->bhlist[pre->nblist++] = bh;
- if (!bh->b_uptodate) bhreq[nbreq++] = bh;
+ if (!msdos_is_uptodate(sb,bh)) bhreq[nbreq++] = bh;
}else{
break;
}
}
- if (nbreq > 0) ll_rw_block (READ,nbreq,bhreq);
+ if (nbreq > 0) msdos_ll_rw_block (sb,READ,nbreq,bhreq);
for (i=pre->nblist; i<MSDOS_PREFETCH; i++) pre->bhlist[i] = NULL;
}
@@ -103,6 +156,7 @@ int msdos_file_read(
char *buf,
int count)
{
+ struct super_block *sb = inode->i_sb;
char *start = buf;
char *end = buf + count;
int i;
@@ -172,7 +226,7 @@ int msdos_file_read(
}
PRINTK (("file_read pos %ld nblist %d %d %d\n",filp->f_pos,pre.nblist,pre.fetched,count));
wait_on_buffer(bh);
- if (!bh->b_uptodate){
+ if (!msdos_is_uptodate(sb,bh)){
/* read error ? */
brelse (bh);
break;
@@ -216,6 +270,7 @@ int msdos_file_write(
char *buf,
int count)
{
+ struct super_block *sb = inode->i_sb;
int sector,offset,size,left,written;
int error,carry;
char *start,*to,ch;
@@ -258,7 +313,7 @@ int msdos_file_write(
error = -EIO;
break;
}
- }else if (!(bh = msdos_sread(inode->i_dev,sector))) {
+ }else if (!(bh = bread(inode->i_dev,sector,SECTOR_SIZE))) {
error = -EIO;
break;
}
@@ -292,7 +347,7 @@ int msdos_file_write(
inode->i_size = filp->f_pos;
inode->i_dirt = 1;
}
- bh->b_uptodate = 1;
+ msdos_set_uptodate(sb,bh,1);
mark_buffer_dirty(bh, 0);
brelse(bh);
}
diff --git a/fs/msdos/inode.c b/fs/msdos/inode.c
index e0577fbef..9302de2a9 100644
--- a/fs/msdos/inode.c
+++ b/fs/msdos/inode.c
@@ -4,6 +4,14 @@
* Written 1992,1993 by Werner Almesberger
*/
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
#include <linux/msdos_fs.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -11,14 +19,12 @@
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/major.h>
+#include <linux/blkdev.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/locks.h>
-#ifdef MODULE
- #include <linux/module.h>
- #include "../../tools/version.h"
-#endif
+#include "msbuffer.h"
#include <asm/segment.h>
@@ -40,9 +46,8 @@ void msdos_put_inode(struct inode *inode)
clear_inode(inode);
if (depend) {
if (MSDOS_I(depend)->i_old != inode) {
- printk("Invalid link (0x%X): expected 0x%X, got 0x%X\n",
- (int) depend,(int) inode,(int) MSDOS_I(depend)->
- i_old);
+ printk("Invalid link (0x%p): expected 0x%p, got 0x%p\n",
+ depend, inode, MSDOS_I(depend)->i_old);
fs_panic(sb,"...");
return;
}
@@ -59,9 +64,7 @@ void msdos_put_super(struct super_block *sb)
lock_super(sb);
sb->s_dev = 0;
unlock_super(sb);
- #ifdef MODULE
- MOD_DEC_USE_COUNT;
- #endif
+ MOD_DEC_USE_COUNT;
return;
}
@@ -79,7 +82,8 @@ static struct super_operations msdos_sops = {
static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
- gid_t *gid,int *umask,int *debug,int *fat,int *quiet)
+ gid_t *gid,int *umask,int *debug,int *fat,int *quiet,
+ int *blksize)
{
char *this_char,*value;
@@ -145,6 +149,14 @@ static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
if (value) return 0;
*quiet = 1;
}
+ else if (!strcmp(this_char,"blocksize")) {
+ *blksize = simple_strtoul(value,&value,0);
+ if (*value)
+ return 0;
+ if (*blksize != 512 && *blksize != 1024){
+ printk ("MSDOS FS: Invalid blocksize (512 or 1024)\n");
+ }
+ }
else return 0;
}
return 1;
@@ -153,7 +165,7 @@ static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
/* Read the super block of an MS-DOS FS. */
-struct super_block *msdos_read_super(struct super_block *s,void *data,
+struct super_block *msdos_read_super(struct super_block *sb,void *data,
int silent)
{
struct buffer_head *bh;
@@ -164,28 +176,38 @@ struct super_block *msdos_read_super(struct super_block *s,void *data,
uid_t uid;
gid_t gid;
int umask;
+ int blksize = 512;
+ MOD_INC_USE_COUNT;
+ if (hardsect_size[MAJOR(sb->s_dev)] != NULL){
+ blksize = hardsect_size[MAJOR(sb->s_dev)][MINOR(sb->s_dev)];
+ if (blksize != 512){
+ printk ("MSDOS: Hardware sector size is %d\n",blksize);
+ }
+ }
if (!parse_options((char *) data,&check,&conversion,&uid,&gid,&umask,
- &debug,&fat,&quiet)) {
- s->s_dev = 0;
+ &debug,&fat,&quiet,&blksize)
+ || (blksize != 512 && blksize != 1024)) {
+ sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
return NULL;
}
cache_init();
- lock_super(s);
- set_blocksize(s->s_dev, SECTOR_SIZE);
- bh = bread(s->s_dev, 0, SECTOR_SIZE);
- unlock_super(s);
- if (bh == NULL) {
- s->s_dev = 0;
+ lock_super(sb);
+ /* The first read is always 1024 bytes */
+ sb->s_blocksize = 1024;
+ set_blocksize(sb->s_dev, 1024);
+ bh = bread(sb->s_dev, 0, 1024);
+ unlock_super(sb);
+ if (bh == NULL || !msdos_is_uptodate(sb,bh)) {
+ brelse (bh);
+ sb->s_dev = 0;
printk("MSDOS bread failed\n");
+ MOD_DEC_USE_COUNT;
return NULL;
}
b = (struct msdos_boot_sector *) bh->b_data;
- s->s_blocksize = 512; /* Using this small block size solve the */
- /* the misfit with buffer cache and cluster */
- /* because cluster (DOS) are often aligned */
- /* on odd sector */
- s->s_blocksize_bits = 9; /* we cannot handle anything else yet */
+ set_blocksize(sb->s_dev, blksize);
/*
* The DOS3 partition size limit is *not* 32M as many people think.
* Instead, it is 64K sectors (with the usual sector size being
@@ -206,85 +228,92 @@ struct super_block *msdos_read_super(struct super_block *s,void *data,
logical_sector_size = CF_LE_W(*(unsigned short *) &b->sector_size);
sector_mult = logical_sector_size >> SECTOR_BITS;
- MSDOS_SB(s)->cluster_size = b->cluster_size*sector_mult;
- MSDOS_SB(s)->fats = b->fats;
- MSDOS_SB(s)->fat_start = CF_LE_W(b->reserved)*sector_mult;
- MSDOS_SB(s)->fat_length = CF_LE_W(b->fat_length)*sector_mult;
- MSDOS_SB(s)->dir_start = (CF_LE_W(b->reserved)+b->fats*CF_LE_W(
+ MSDOS_SB(sb)->cluster_size = b->cluster_size*sector_mult;
+ MSDOS_SB(sb)->fats = b->fats;
+ MSDOS_SB(sb)->fat_start = CF_LE_W(b->reserved)*sector_mult;
+ MSDOS_SB(sb)->fat_length = CF_LE_W(b->fat_length)*sector_mult;
+ MSDOS_SB(sb)->dir_start = (CF_LE_W(b->reserved)+b->fats*CF_LE_W(
b->fat_length))*sector_mult;
- MSDOS_SB(s)->dir_entries = CF_LE_W(*((unsigned short *) &b->dir_entries
+ MSDOS_SB(sb)->dir_entries = CF_LE_W(*((unsigned short *) &b->dir_entries
));
- MSDOS_SB(s)->data_start = MSDOS_SB(s)->dir_start+ROUND_TO_MULTIPLE((
- MSDOS_SB(s)->dir_entries << MSDOS_DIR_BITS) >> SECTOR_BITS,
+ MSDOS_SB(sb)->data_start = MSDOS_SB(sb)->dir_start+ROUND_TO_MULTIPLE((
+ MSDOS_SB(sb)->dir_entries << MSDOS_DIR_BITS) >> SECTOR_BITS,
sector_mult);
data_sectors = (CF_LE_W(*((unsigned short *) &b->sectors)) ?
CF_LE_W(*((unsigned short *) &b->sectors)) :
- CF_LE_L(b->total_sect))*sector_mult-MSDOS_SB(s)->data_start;
+ CF_LE_L(b->total_sect))*sector_mult-MSDOS_SB(sb)->data_start;
error = !b->cluster_size || !sector_mult;
if (!error) {
- MSDOS_SB(s)->clusters = b->cluster_size ? data_sectors/
+ MSDOS_SB(sb)->clusters = b->cluster_size ? data_sectors/
b->cluster_size/sector_mult : 0;
- MSDOS_SB(s)->fat_bits = fat ? fat : MSDOS_SB(s)->clusters >
+ MSDOS_SB(sb)->fat_bits = fat ? fat : MSDOS_SB(sb)->clusters >
MSDOS_FAT12 ? 16 : 12;
- error = !MSDOS_SB(s)->fats || (MSDOS_SB(s)->dir_entries &
- (MSDOS_DPS-1)) || MSDOS_SB(s)->clusters+2 > MSDOS_SB(s)->
- fat_length*SECTOR_SIZE*8/MSDOS_SB(s)->fat_bits ||
+ error = !MSDOS_SB(sb)->fats || (MSDOS_SB(sb)->dir_entries &
+ (MSDOS_DPS-1)) || MSDOS_SB(sb)->clusters+2 > MSDOS_SB(sb)->
+ fat_length*SECTOR_SIZE*8/MSDOS_SB(sb)->fat_bits ||
(logical_sector_size & (SECTOR_SIZE-1)) || !b->secs_track ||
!b->heads;
}
brelse(bh);
+ /*
+ This must be done after the brelse because the bh is a dummy
+ allocated by msdos_bread (see buffer.c)
+ */
+ sb->s_blocksize = blksize; /* Using this small block size solve the */
+ /* the misfit with buffer cache and cluster */
+ /* because cluster (DOS) are often aligned */
+ /* on odd sector */
+ sb->s_blocksize_bits = blksize == 512 ? 9 : 10;
if (error || debug) {
/* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
- "uid=%d,gid=%d,umask=%03o%s]\n",MSDOS_SB(s)->fat_bits,check,
- conversion,uid,gid,umask,MSDOS_CAN_BMAP(MSDOS_SB(s)) ?
+ "uid=%d,gid=%d,umask=%03o%s]\n",MSDOS_SB(sb)->fat_bits,check,
+ conversion,uid,gid,umask,MSDOS_CAN_BMAP(MSDOS_SB(sb)) ?
",bmap" : "");
printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,"
- "se=%d,ts=%ld,ls=%d]\n",b->media,MSDOS_SB(s)->cluster_size,
- MSDOS_SB(s)->fats,MSDOS_SB(s)->fat_start,MSDOS_SB(s)->
- fat_length,MSDOS_SB(s)->dir_start,MSDOS_SB(s)->dir_entries,
- MSDOS_SB(s)->data_start,CF_LE_W(*(unsigned short *) &b->
- sectors),b->total_sect,logical_sector_size);
+ "se=%d,ts=%ld,ls=%d]\n",b->media,MSDOS_SB(sb)->cluster_size,
+ MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start,MSDOS_SB(sb)->
+ fat_length,MSDOS_SB(sb)->dir_start,MSDOS_SB(sb)->dir_entries,
+ MSDOS_SB(sb)->data_start,CF_LE_W(*(unsigned short *) &b->
+ sectors),(unsigned long)b->total_sect,logical_sector_size);
+ printk ("Transaction block size = %d\n",blksize);
}
if (error) {
if (!silent)
printk("VFS: Can't find a valid MSDOS filesystem on dev 0x%04x.\n",
- s->s_dev);
- s->s_dev = 0;
+ sb->s_dev);
+ sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
return NULL;
}
- s->s_magic = MSDOS_SUPER_MAGIC;
- MSDOS_SB(s)->name_check = check;
- MSDOS_SB(s)->conversion = conversion;
+ sb->s_magic = MSDOS_SUPER_MAGIC;
+ MSDOS_SB(sb)->name_check = check;
+ MSDOS_SB(sb)->conversion = conversion;
/* set up enough so that it can read an inode */
- s->s_op = &msdos_sops;
- MSDOS_SB(s)->fs_uid = uid;
- MSDOS_SB(s)->fs_gid = gid;
- MSDOS_SB(s)->fs_umask = umask;
- MSDOS_SB(s)->quiet = quiet;
- MSDOS_SB(s)->free_clusters = -1; /* don't know yet */
- MSDOS_SB(s)->fat_wait = NULL;
- MSDOS_SB(s)->fat_lock = 0;
- MSDOS_SB(s)->prev_free = 0;
- if (!(s->s_mounted = iget(s,MSDOS_ROOT_INO))) {
- s->s_dev = 0;
+ sb->s_op = &msdos_sops;
+ MSDOS_SB(sb)->fs_uid = uid;
+ MSDOS_SB(sb)->fs_gid = gid;
+ MSDOS_SB(sb)->fs_umask = umask;
+ MSDOS_SB(sb)->quiet = quiet;
+ MSDOS_SB(sb)->free_clusters = -1; /* don't know yet */
+ MSDOS_SB(sb)->fat_wait = NULL;
+ MSDOS_SB(sb)->fat_lock = 0;
+ MSDOS_SB(sb)->prev_free = 0;
+ if (!(sb->s_mounted = iget(sb,MSDOS_ROOT_INO))) {
+ sb->s_dev = 0;
printk("get root inode failed\n");
+ MOD_DEC_USE_COUNT;
return NULL;
}
- #ifdef MODULE
- MOD_INC_USE_COUNT;
- #endif
- return s;
+ return sb;
}
-void msdos_statfs(struct super_block *sb,struct statfs *buf)
+void msdos_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
{
int free,nr;
+ struct statfs tmp;
- put_fs_long(sb->s_magic,&buf->f_type);
- put_fs_long(MSDOS_SB(sb)->cluster_size*SECTOR_SIZE,&buf->f_bsize);
- put_fs_long(MSDOS_SB(sb)->clusters,&buf->f_blocks);
lock_fat(sb);
if (MSDOS_SB(sb)->free_clusters != -1)
free = MSDOS_SB(sb)->free_clusters;
@@ -295,11 +324,15 @@ void msdos_statfs(struct super_block *sb,struct statfs *buf)
MSDOS_SB(sb)->free_clusters = free;
}
unlock_fat(sb);
- put_fs_long(free,&buf->f_bfree);
- put_fs_long(free,&buf->f_bavail);
- put_fs_long(0,&buf->f_files);
- put_fs_long(0,&buf->f_ffree);
- put_fs_long(12,&buf->f_namelen);
+ tmp.f_type = sb->s_magic;
+ tmp.f_bsize = MSDOS_SB(sb)->cluster_size*SECTOR_SIZE;
+ tmp.f_blocks = MSDOS_SB(sb)->clusters;
+ tmp.f_bfree = free;
+ tmp.f_bavail = free;
+ tmp.f_files = 0;
+ tmp.f_ffree = 0;
+ tmp.f_namelen = 12;
+ memcpy_tofs(buf, &tmp, bufsiz);
}
@@ -321,6 +354,7 @@ int msdos_bmap(struct inode *inode,int block)
void msdos_read_inode(struct inode *inode)
{
+ struct super_block *sb = inode->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *raw_entry;
int nr;
@@ -384,7 +418,9 @@ void msdos_read_inode(struct inode *inode)
inode->i_mode = MSDOS_MKMODE(raw_entry->attr,(IS_NOEXEC(inode)
? S_IRUGO|S_IWUGO : S_IRWXUGO) & ~MSDOS_SB(inode->i_sb)->fs_umask) |
S_IFREG;
- inode->i_op = &msdos_file_inode_operations; /* Now can always bmap */
+ inode->i_op = sb->s_blocksize == 1024
+ ? &msdos_file_inode_operations_1024
+ : &msdos_file_inode_operations;
MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start);
inode->i_nlink = 1;
inode->i_size = CF_LE_L(raw_entry->size);
@@ -404,6 +440,7 @@ void msdos_read_inode(struct inode *inode)
void msdos_write_inode(struct inode *inode)
{
+ struct super_block *sb = inode->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *raw_entry;
@@ -482,12 +519,7 @@ int init_module(void)
void cleanup_module(void)
{
- if (MOD_IN_USE)
- printk("msdos: device busy, remove delayed\n");
- else
- {
- unregister_filesystem(&msdos_fs_type);
- }
+ unregister_filesystem(&msdos_fs_type);
}
#endif
diff --git a/fs/msdos/misc.c b/fs/msdos/misc.c
index 630198afa..3b3218b32 100644
--- a/fs/msdos/misc.c
+++ b/fs/msdos/misc.c
@@ -4,6 +4,10 @@
* Written 1992,1993 by Werner Almesberger
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/fs.h>
#include <linux/msdos_fs.h>
#include <linux/sched.h>
@@ -12,8 +16,10 @@
#include <linux/string.h>
#include <linux/stat.h>
+#include "msbuffer.h"
#define PRINTK(x)
+#define Printk(x) printk x
/* Well-known binary file extensions */
static char bin_extensions[] =
@@ -111,7 +117,8 @@ void unlock_fat(struct super_block *sb)
int msdos_add_cluster(struct inode *inode)
{
- int count,nr,limit,last,current,sector,last_sector;
+ struct super_block *sb = inode->i_sb;
+ int count,nr,limit,last,current,sector,last_sector,file_cluster;
struct buffer_head *bh;
int cluster_size = MSDOS_SB(inode->i_sb)->cluster_size;
@@ -124,6 +131,7 @@ int msdos_add_cluster(struct inode *inode)
nr = ((count+MSDOS_SB(inode->i_sb)->prev_free) % limit)+2;
if (fat_access(inode->i_sb,nr,-1) == 0) break;
}
+ PRINTK (("cnt = %d --",count));
#ifdef DEBUG
printk("free cluster: %d\n",nr);
#endif
@@ -143,14 +151,30 @@ printk("free cluster: %d\n",nr);
printk("set to %x\n",fat_access(inode->i_sb,nr,-1));
#endif
last = 0;
+ /* We must locate the last cluster of the file to add this
+ new one (nr) to the end of the link list (the FAT).
+
+ Here file_cluster will be the number of the last cluster of the
+ file (before we add nr).
+
+ last is the corresponding cluster number on the disk. We will
+ use last to plug the nr cluster. We will use file_cluster to
+ update the cache.
+ */
+ file_cluster = 0;
if ((current = MSDOS_I(inode)->i_start) != 0) {
cache_lookup(inode,INT_MAX,&last,&current);
- while (current && current != -1)
+ file_cluster = last;
+ while (current && current != -1){
+ PRINTK (("."));
+ file_cluster++;
if (!(current = fat_access(inode->i_sb,
last = current,-1))) {
fs_panic(inode->i_sb,"File without EOF");
return -ENOSPC;
}
+ }
+ PRINTK ((" -- "));
}
#ifdef DEBUG
printk("last = %d\n",last);
@@ -173,11 +197,17 @@ if (last) printk("next set to %d\n",fat_access(inode->i_sb,last,-1));
printk("getblk failed\n");
else {
memset(bh->b_data,0,SECTOR_SIZE);
- bh->b_uptodate = 1;
+ msdos_set_uptodate(sb,bh,1);
mark_buffer_dirty(bh, 1);
brelse(bh);
}
}
+ if (file_cluster != inode->i_blocks/cluster_size){
+ printk ("file_cluster badly computed!!! %d <> %ld\n"
+ ,file_cluster,inode->i_blocks/cluster_size);
+ }else{
+ cache_add(inode,file_cluster,nr);
+ }
inode->i_blocks += cluster_size;
if (S_ISDIR(inode->i_mode)) {
if (inode->i_size & (SECTOR_SIZE-1)) {
@@ -255,6 +285,7 @@ void date_unix2dos(int unix_date,unsigned short *time,
int msdos_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
struct msdos_dir_entry **de)
{
+ struct super_block *sb = dir->i_sb;
int sector,offset;
while (1) {
@@ -269,7 +300,7 @@ int msdos_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
if (*bh)
brelse(*bh);
PRINTK (("get_entry sector apres brelse\n"));
- if (!(*bh = msdos_sread(dir->i_dev,sector))) {
+ if (!(*bh = bread(dir->i_dev,sector,SECTOR_SIZE))) {
printk("Directory sread (sector %d) failed\n",sector);
continue;
}
@@ -343,7 +374,7 @@ static int raw_scan_sector(struct super_block *sb,int sector,char *name,
struct inode *inode;
int entry,start,done;
- if (!(bh = msdos_sread(sb->s_dev,sector))) return -EIO;
+ if (!(bh = bread(sb->s_dev,sector,SECTOR_SIZE))) return -EIO;
data = (struct msdos_dir_entry *) bh->b_data;
for (entry = 0; entry < MSDOS_DPS; entry++) {
if (name) RSS_NAME
diff --git a/fs/msdos/mmap.c b/fs/msdos/mmap.c
index 0e85584e9..97ffa0bb1 100644
--- a/fs/msdos/mmap.c
+++ b/fs/msdos/mmap.c
@@ -6,6 +6,10 @@
*
* msdos mmap handling
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -48,6 +52,7 @@ static unsigned long msdos_file_mmap_nopage(
if (gap < PAGE_SIZE){
clear = PAGE_SIZE - gap;
}
+ filp.f_reada = 0;
filp.f_pos = pos;
need_read = PAGE_SIZE - clear;
{
@@ -71,10 +76,14 @@ static unsigned long msdos_file_mmap_nopage(
struct vm_operations_struct msdos_file_mmap = {
NULL, /* open */
NULL, /* close */
+ NULL, /* unmap */
+ NULL, /* protect */
+ NULL, /* sync */
+ NULL, /* advise */
msdos_file_mmap_nopage, /* nopage */
NULL, /* wppage */
- NULL, /* share */
- NULL, /* unmap */
+ NULL, /* swapout */
+ NULL, /* swapin */
};
/*
@@ -83,7 +92,7 @@ struct vm_operations_struct msdos_file_mmap = {
*/
int msdos_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
{
- if (vma->vm_page_prot & PAGE_RW) /* only PAGE_COW or read-only supported now */
+ 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;
@@ -100,3 +109,4 @@ int msdos_mmap(struct inode * inode, struct file * file, struct vm_area_struct *
return 0;
}
+
diff --git a/fs/msdos/msbuffer.h b/fs/msdos/msbuffer.h
new file mode 100644
index 000000000..ecd736149
--- /dev/null
+++ b/fs/msdos/msbuffer.h
@@ -0,0 +1,34 @@
+/* buffer.c 13/12/94 20.19.10 */
+struct buffer_head *msdos_bread (struct super_block *sb, int block);
+struct buffer_head *msdos_getblk (struct super_block *sb, int block);
+void msdos_brelse (struct super_block *sb, struct buffer_head *bh);
+void msdos_mark_buffer_dirty (struct super_block *sb,
+ struct buffer_head *bh,
+ int dirty_val);
+void msdos_set_uptodate (struct super_block *sb,
+ struct buffer_head *bh,
+ int val);
+int msdos_is_uptodate (struct super_block *sb, struct buffer_head *bh);
+void msdos_ll_rw_block (struct super_block *sb, int opr,
+ int nbreq, struct buffer_head *bh[32]);
+
+/* These macros exist to avoid modifying all the code */
+/* They should be removed one day I guess */
+
+/* The versioning mechanism of the modules system define those macros */
+/* This remove some warnings */
+#ifdef brelse
+ #undef brelse
+#endif
+#ifdef bread
+ #undef bread
+#endif
+#ifdef getblk
+ #undef getblk
+#endif
+
+#define brelse(b) msdos_brelse(sb,b)
+#define bread(d,b,s) msdos_bread(sb,b)
+#define getblk(d,b,s) msdos_getblk(sb,b)
+#define mark_buffer_dirty(b,v) msdos_mark_buffer_dirty(sb,b,v)
+
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index ad3b9c8bc..ee7a14e36 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -4,6 +4,10 @@
* Written 1992,1993 by Werner Almesberger
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/sched.h>
@@ -13,6 +17,8 @@
#include <linux/string.h>
#include <linux/stat.h>
+#include "msbuffer.h"
+
#define PRINTK(x)
/* MS-DOS "device special files" */
@@ -107,6 +113,7 @@ static int msdos_find(struct inode *dir,const char *name,int len,
int msdos_lookup(struct inode *dir,const char *name,int len,
struct inode **result)
{
+ struct super_block *sb = dir->i_sb;
int ino,res;
struct msdos_dir_entry *de;
struct buffer_head *bh;
@@ -173,6 +180,7 @@ int msdos_lookup(struct inode *dir,const char *name,int len,
static int msdos_create_entry(struct inode *dir,char *name,int is_dir,
struct inode **result)
{
+ struct super_block *sb = dir->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *de;
int res,ino;
@@ -209,6 +217,7 @@ static int msdos_create_entry(struct inode *dir,char *name,int is_dir,
int msdos_create(struct inode *dir,const char *name,int len,int mode,
struct inode **result)
{
+ struct super_block *sb = dir->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *de;
char msdos_name[MSDOS_NAME];
@@ -256,6 +265,7 @@ static void dump_fat(struct super_block *sb,int start)
int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
{
+ struct super_block *sb = dir->i_sb;
struct buffer_head *bh;
struct msdos_dir_entry *de;
struct inode *inode,*dot;
@@ -313,6 +323,7 @@ mkdir_error:
static int msdos_empty(struct inode *dir)
{
+ struct super_block *sb = dir->i_sb;
loff_t pos;
struct buffer_head *bh;
struct msdos_dir_entry *de;
@@ -338,6 +349,7 @@ static int msdos_empty(struct inode *dir)
int msdos_rmdir(struct inode *dir,const char *name,int len)
{
+ struct super_block *sb = dir->i_sb;
int res,ino;
struct buffer_head *bh;
struct msdos_dir_entry *de;
@@ -379,6 +391,7 @@ static int msdos_unlinkx(
int len,
int nospc) /* Flag special file ? */
{
+ struct super_block *sb = dir->i_sb;
int res,ino;
struct buffer_head *bh;
struct msdos_dir_entry *de;
@@ -425,6 +438,7 @@ static int rename_same_dir(struct inode *old_dir,char *old_name,
struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
struct msdos_dir_entry *old_de,int old_ino)
{
+ struct super_block *sb = old_dir->i_sb;
struct buffer_head *new_bh;
struct msdos_dir_entry *new_de;
struct inode *new_inode,*old_inode;
@@ -476,6 +490,7 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
struct msdos_dir_entry *old_de,int old_ino)
{
+ struct super_block *sb = old_dir->i_sb;
struct buffer_head *new_bh,*free_bh,*dotdot_bh;
struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
@@ -594,6 +609,7 @@ rename_done:
int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
struct inode *new_dir,const char *new_name,int new_len)
{
+ struct super_block *sb = old_dir->i_sb;
char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
struct buffer_head *old_bh;
struct msdos_dir_entry *old_de;
diff --git a/fs/namei.c b/fs/namei.c
index e383dff93..e047cde28 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -16,6 +16,7 @@
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
+#include <linux/mm.h>
#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
@@ -31,33 +32,14 @@ static inline int get_max_filename(unsigned long address)
if (get_fs() == KERNEL_DS)
return 0;
- for (vma = current->mm->mmap ; ; vma = vma->vm_next) {
- if (!vma)
- return -EFAULT;
- if (vma->vm_end > address)
- break;
- }
-#if defined (__i386__)
- if (vma->vm_start > address || !(vma->vm_page_prot & PAGE_USER))
-#elif defined (__mips__)
- if (vma->vm_start > address ||
- vma->vm_start >= 0x80000000 || vma->vm_end >= 0x80000000)
-#else
-#error "Architecture not supported."
-#endif
+ vma = find_vma(current, address);
+ if (!vma || vma->vm_start > address || !(vma->vm_flags & VM_READ))
return -EFAULT;
-
address = vma->vm_end - address;
if (address > PAGE_SIZE)
return 0;
if (vma->vm_next && vma->vm_next->vm_start == vma->vm_end &&
-#if defined (__i386__)
- (vma->vm_next->vm_page_prot & PAGE_USER))
-#elif defined (__mips__)
- (vma->vm_start >= 0x80000000 || vma->vm_end >= 0x80000000))
-#else
-#error "Architecture not supported."
-#endif
+ (vma->vm_next->vm_flags & VM_READ))
return 0;
return address;
}
@@ -121,14 +103,14 @@ int permission(struct inode * inode,int mask)
if (inode->i_op && inode->i_op->permission)
return inode->i_op->permission(inode, mask);
else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
- return 0; /* Nobody gets write access to an immutable file */
+ return -EACCES; /* Nobody gets write access to an immutable file */
else if (current->fsuid == inode->i_uid)
mode >>= 6;
else if (in_group_p(inode->i_gid))
mode >>= 3;
if (((mode & mask & 0007) == mask) || fsuser())
- return 1;
- return 0;
+ return 0;
+ return -EACCES;
}
/*
@@ -184,7 +166,6 @@ int lookup(struct inode * dir,const char * name, int len,
*result = dir;
return 0;
} else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) {
- sb = dir->i_sb;
iput(dir);
dir = sb->s_covered;
if (!dir)
@@ -196,9 +177,9 @@ int lookup(struct inode * dir,const char * name, int len,
iput(dir);
return -ENOTDIR;
}
- if (!perm) {
+ if (perm != 0) {
iput(dir);
- return -EACCES;
+ return perm;
}
if (!len) {
*result = dir;
@@ -366,9 +347,9 @@ int open_namei(const char * pathname, int flag, int mode,
return -EISDIR;
}
/* thanks to Paul Pluzhnikov for noticing this was missing.. */
- if (!permission(dir,ACC_MODE(flag))) {
+ if ((error = permission(dir,ACC_MODE(flag))) != 0) {
iput(dir);
- return -EACCES;
+ return error;
}
*res_inode=dir;
return 0;
@@ -382,8 +363,8 @@ int open_namei(const char * pathname, int flag, int mode,
iput(inode);
error = -EEXIST;
}
- } else if (!permission(dir,MAY_WRITE | MAY_EXEC))
- error = -EACCES;
+ } else if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
+ ; /* error is already set! */
else if (!dir->i_op || !dir->i_op->create)
error = -EACCES;
else if (IS_RDONLY(dir))
@@ -409,9 +390,9 @@ int open_namei(const char * pathname, int flag, int mode,
iput(inode);
return -EISDIR;
}
- if (!permission(inode,ACC_MODE(flag))) {
+ if ((error = permission(inode,ACC_MODE(flag))) != 0) {
iput(inode);
- return -EACCES;
+ return error;
}
if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
if (IS_NODEV(inode)) {
@@ -474,9 +455,9 @@ int do_mknod(const char * filename, int mode, dev_t dev)
iput(dir);
return -EROFS;
}
- if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
+ if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
iput(dir);
- return -EACCES;
+ return error;
}
if (!dir->i_op || !dir->i_op->mknod) {
iput(dir);
@@ -531,9 +512,9 @@ static int do_mkdir(const char * pathname, int mode)
iput(dir);
return -EROFS;
}
- if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
+ if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
iput(dir);
- return -EACCES;
+ return error;
}
if (!dir->i_op || !dir->i_op->mkdir) {
iput(dir);
@@ -577,9 +558,9 @@ static int do_rmdir(const char * name)
iput(dir);
return -EROFS;
}
- if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
+ if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
iput(dir);
- return -EACCES;
+ return error;
}
/*
* A subdirectory cannot be removed from an append-only directory
@@ -625,9 +606,9 @@ static int do_unlink(const char * name)
iput(dir);
return -EROFS;
}
- if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
+ if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
iput(dir);
- return -EACCES;
+ return error;
}
/*
* A file cannot be removed from an append-only directory
@@ -673,9 +654,9 @@ static int do_symlink(const char * oldname, const char * newname)
iput(dir);
return -EROFS;
}
- if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
+ if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
iput(dir);
- return -EACCES;
+ return error;
}
if (!dir->i_op || !dir->i_op->symlink) {
iput(dir);
@@ -732,10 +713,10 @@ static int do_link(struct inode * oldinode, const char * newname)
iput(oldinode);
return -EXDEV;
}
- if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
+ if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
iput(dir);
iput(oldinode);
- return -EACCES;
+ return error;
}
/*
* A link to an append-only or immutable file cannot be created
@@ -786,9 +767,9 @@ static int do_rename(const char * oldname, const char * newname)
error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
if (error)
return error;
- if (!permission(old_dir,MAY_WRITE | MAY_EXEC)) {
+ if ((error = permission(old_dir,MAY_WRITE | MAY_EXEC)) != 0) {
iput(old_dir);
- return -EACCES;
+ return error;
}
if (!old_len || (old_base[0] == '.' &&
(old_len == 1 || (old_base[1] == '.' &&
@@ -801,10 +782,10 @@ static int do_rename(const char * oldname, const char * newname)
iput(old_dir);
return error;
}
- if (!permission(new_dir,MAY_WRITE | MAY_EXEC)) {
+ if ((error = permission(new_dir,MAY_WRITE | MAY_EXEC)) != 0){
iput(old_dir);
iput(new_dir);
- return -EACCES;
+ return error;
}
if (!new_len || (new_base[0] == '.' &&
(new_len == 1 || (new_base[1] == '.' &&
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 8610c95b1..eabf9f6f1 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -23,6 +23,8 @@ nfs.o: $(OBJS)
dep:
$(CPP) -M *.c > .depend
+modules: nfs.o
+
#
# include a dependency file if one exists
#
diff --git a/fs/nfs/cache.c b/fs/nfs/cache.c
new file mode 100644
index 000000000..57f3cc411
--- /dev/null
+++ b/fs/nfs/cache.c
@@ -0,0 +1,63 @@
+
+void nfs_bl_cache_invalidate(nfs_cache *nh)
+{
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ if(nh->inuse)
+ nh->dead=1;
+ else
+ {
+ kfree_s(nh->data);
+ nh->data=NULL;
+ nh->free=1;
+ }
+}
+
+void nfs_bl_cache_revalidate(nfs_cache *nh, struct fattr fa)
+{
+ nh->fattr=fattr;
+ nh->time=jiffies;
+}
+
+/*
+ * Find a block in the cache. We know the cache is block sized in block
+ * aligned space.
+ */
+
+nfs_cache *nfs_cache_find(struct inode *inode, off_t pos)
+{
+ nfs_cache *nh=&nfs_cache_slot[0];
+ nfs_cache *ffree=NULL;
+ struct nfs_fattr fattr;
+ int ct=0;
+ while(ct<NH_CACHE_SIZE)
+ {
+ if(nh->inode_num==inode->i_no && !nh->dead&&!nh->free&&nh->file_pos==pos)
+ {
+ if(abs(jiffies-nh->time)<EXPIRE_CACHE)
+ return nh;
+ /*
+ * Revalidate
+ */
+
+ if(nfs_proc_getattr(NFS_SERVER(inode), NFS_FH(inode), &fattr))
+ {
+ nfs_bl_cache_invalidate(nh);
+ continue; /* get attr failed */
+ }
+ if(nh->fattr.modified!=fattr.modified)
+ {
+ nfs_bl_cache_invalidate(nh);
+ continue; /* cache is out of date */
+ }
+ nfs_refresh_inode(inode, fattr);
+ nh->fattr=fattr;
+ nfs_bl_cache_revalidate(nh);
+ return nh;
+ }
+ if(nh->free)
+ ffree=nh;
+ }
+ return ffree;
+}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 62a3e0821..bdbe92d0f 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -6,6 +6,10 @@
* nfs directory handling functions
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/stat.h>
@@ -18,12 +22,9 @@
#include <asm/segment.h> /* for fs functions */
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+3) & ~3)
-
static int nfs_dir_read(struct inode *, struct file *filp, char *buf,
int count);
-static int nfs_readdir(struct inode *, struct file *, struct dirent *, int);
+static int nfs_readdir(struct inode *, struct file *, void *, filldir_t);
static int nfs_lookup(struct inode *dir, const char *name, int len,
struct inode **result);
static int nfs_create(struct inode *dir, const char *name, int len, int mode,
@@ -87,7 +88,7 @@ static int nfs_dir_read(struct inode *inode, struct file *filp, char *buf,
*/
static int nfs_readdir(struct inode *inode, struct file *filp,
- struct dirent *dirent, int count)
+ void *dirent, filldir_t filldir)
{
static int c_dev = 0;
static int c_ino;
@@ -95,7 +96,7 @@ static int nfs_readdir(struct inode *inode, struct file *filp,
static struct nfs_entry *c_entry = NULL;
int result;
- int i;
+ int i, index = 0;
struct nfs_entry *entry;
if (!inode || !S_ISDIR(inode->i_mode)) {
@@ -125,7 +126,7 @@ static int nfs_readdir(struct inode *inode, struct file *filp,
return 0;
}
else
- entry = c_entry + i + 1;
+ entry = c_entry + (index = i + 1);
break;
}
}
@@ -144,19 +145,27 @@ static int nfs_readdir(struct inode *inode, struct file *filp,
c_dev = inode->i_dev;
c_ino = inode->i_ino;
c_size = result;
- entry = c_entry + 0;
+ entry = c_entry + (index = 0);
}
}
/* if we found it in the cache or from an nfs call, return results */
-
- if (entry) {
- i = strlen(entry->name);
- memcpy_tofs(dirent->d_name, entry->name, i + 1);
- put_fs_long(entry->fileid, &dirent->d_ino);
- put_fs_word(i, &dirent->d_reclen);
- filp->f_pos = entry->cookie;
- return ROUND_UP(NAME_OFFSET(dirent)+i+1);
+ if (!entry)
+ return 0;
+ while (index < c_size) {
+ int nextpos = entry->cookie;
+ if (filldir(dirent, entry->name, strlen(entry->name), filp->f_pos, entry->fileid) < 0)
+ break;
+ filp->f_pos = nextpos;
+ /* revalidate the cache if we slept in filldir() */
+ if (inode->i_dev != c_dev)
+ break;
+ if (inode->i_ino != c_ino)
+ break;
+ if (nextpos != entry->cookie)
+ break;
+ index++;
+ entry++;
}
return 0;
}
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index e71d29483..cf8fe83ce 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -14,6 +14,10 @@
* nfs regular file handling functions
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <asm/system.h>
@@ -119,7 +123,7 @@ static int nfs_file_read(struct inode *inode, struct file *file, char *buf,
if ((cache[i].inode_num == inode->i_ino)
&& (cache[i].file_pos <= pos)
&& (cache[i].file_pos + cache[i].len >= pos + count)
- && (abs(jiffies - cache[i].time) <= EXPIRE_CACHE))
+ && (abs(jiffies - cache[i].time) < EXPIRE_CACHE))
break;
if (i < READ_CACHE_SIZE) {
++cache[i].in_use;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 17f2cb6f0..94b4b4557 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -4,8 +4,19 @@
* Copyright (C) 1992 Rick Sladkey
*
* nfs inode and superblock handling functions
+ *
+ * Modularised by Alan Cox <Alan.Cox@linux.org>, while hacking some
+ * experimental NFS changes. Modularisation taken straight from SYS5 fs.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
#include <asm/system.h>
#include <asm/segment.h>
@@ -18,12 +29,12 @@
#include <linux/errno.h>
#include <linux/locks.h>
-extern int close_fp(struct file *filp, unsigned int fd);
+extern int close_fp(struct file *filp);
static int nfs_notify_change(struct inode *, struct iattr *);
static void nfs_put_inode(struct inode *);
static void nfs_put_super(struct super_block *);
-static void nfs_statfs(struct super_block *, struct statfs *);
+static void nfs_statfs(struct super_block *, struct statfs *, int bufsiz);
static struct super_operations nfs_sops = {
NULL, /* read inode */
@@ -43,11 +54,11 @@ static void nfs_put_inode(struct inode * inode)
void nfs_put_super(struct super_block *sb)
{
- /* No locks should be open on this, so 0 should be safe as a fd. */
- close_fp(sb->u.nfs_sb.s_server.file, 0);
+ close_fp(sb->u.nfs_sb.s_server.file);
lock_super(sb);
sb->s_dev = 0;
unlock_super(sb);
+ MOD_DEC_USE_COUNT;
}
/*
@@ -67,9 +78,11 @@ struct super_block *nfs_read_super(struct super_block *sb, void *raw_data,
struct file *filp;
dev_t dev = sb->s_dev;
+ MOD_INC_USE_COUNT;
if (!data) {
printk("nfs_read_super: missing data argument\n");
sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
return NULL;
}
fd = data->fd;
@@ -80,11 +93,13 @@ struct super_block *nfs_read_super(struct super_block *sb, void *raw_data,
if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) {
printk("nfs_read_super: invalid file descriptor\n");
sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
return NULL;
}
if (!S_ISSOCK(filp->f_inode->i_mode)) {
printk("nfs_read_super: not a socket\n");
sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
return NULL;
}
filp->f_count++;
@@ -121,32 +136,33 @@ struct super_block *nfs_read_super(struct super_block *sb, void *raw_data,
if (!(sb->s_mounted = nfs_fhget(sb, &data->root, NULL))) {
sb->s_dev = 0;
printk("nfs_read_super: get root inode failed\n");
+ MOD_DEC_USE_COUNT;
return NULL;
}
return sb;
}
-void nfs_statfs(struct super_block *sb, struct statfs *buf)
+void nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
int error;
struct nfs_fsinfo res;
+ struct statfs tmp;
- put_fs_long(NFS_SUPER_MAGIC, &buf->f_type);
error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root,
&res);
if (error) {
printk("nfs_statfs: statfs error = %d\n", -error);
res.bsize = res.blocks = res.bfree = res.bavail = 0;
}
- put_fs_long(res.bsize, &buf->f_bsize);
- put_fs_long(res.blocks, &buf->f_blocks);
- put_fs_long(res.bfree, &buf->f_bfree);
- put_fs_long(res.bavail, &buf->f_bavail);
- put_fs_long(0, &buf->f_files);
- put_fs_long(0, &buf->f_ffree);
- /* We should really try to interrogate the remote server to find
- it's maximum name length here */
- put_fs_long(NAME_MAX, &buf->f_namelen);
+ tmp.f_type = NFS_SUPER_MAGIC;
+ tmp.f_bsize = res.bsize;
+ tmp.f_blocks = res.blocks;
+ tmp.f_bfree = res.bfree;
+ tmp.f_bavail = res.bavail;
+ tmp.f_files = 0;
+ tmp.f_ffree = 0;
+ tmp.f_namelen = NAME_MAX;
+ memcpy_tofs(buf, &tmp, bufsiz);
}
/*
@@ -238,3 +254,26 @@ int nfs_notify_change(struct inode *inode, struct iattr *attr)
inode->i_dirt = 0;
return error;
}
+
+#ifdef MODULE
+
+/* Every kernel module contains stuff like this. */
+
+char kernel_version[] = UTS_RELEASE;
+
+static struct file_system_type nfs_fs_type = {
+ nfs_read_super, "nfs", 0, NULL
+};
+
+int init_module(void)
+{
+ register_filesystem(&nfs_fs_type);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unregister_filesystem(&nfs_fs_type);
+}
+
+#endif
diff --git a/fs/nfs/mmap.c b/fs/nfs/mmap.c
index 811176a69..30854469c 100644
--- a/fs/nfs/mmap.c
+++ b/fs/nfs/mmap.c
@@ -9,6 +9,10 @@
* Copyright (C) 1993
*
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -74,20 +78,25 @@ static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area,
}
return page;
}
+
struct vm_operations_struct nfs_file_mmap = {
NULL, /* open */
NULL, /* close */
+ NULL, /* unmap */
+ NULL, /* protect */
+ NULL, /* sync */
+ NULL, /* advise */
nfs_file_mmap_nopage, /* nopage */
NULL, /* wppage */
- NULL, /* share */
- NULL, /* unmap */
+ NULL, /* swapout */
+ NULL, /* swapin */
};
/* This is used for a general mmap of a nfs file */
int nfs_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
{
- if (vma->vm_page_prot & PAGE_RW) /* only PAGE_COW or read-only supported now */
+ if (vma->vm_flags & VM_SHARED) /* only PAGE_COW or read-only supported now */
return -EINVAL;
if (!inode->i_sb || !S_ISREG(inode->i_mode))
return -EACCES;
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index fd01dad99..9aeb66751 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -33,7 +33,10 @@
#define NFS_PROC_DEBUG
#endif
-#include <linux/config.h>
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/param.h>
#include <linux/sched.h>
#include <linux/mm.h>
@@ -898,6 +901,7 @@ static struct {
{ NFSERR_NOENT, ENOENT },
{ NFSERR_IO, errno_NFSERR_IO },
{ NFSERR_NXIO, ENXIO },
+ { NFSERR_EAGAIN, EAGAIN },
{ NFSERR_ACCES, EACCES },
{ NFSERR_EXIST, EEXIST },
{ NFSERR_NODEV, ENODEV },
diff --git a/fs/nfs/sock.c b/fs/nfs/sock.c
index 2455d938a..ea81f55af 100644
--- a/fs/nfs/sock.c
+++ b/fs/nfs/sock.c
@@ -18,7 +18,10 @@
*
*/
-#include <linux/config.h>
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/sched.h>
#include <linux/nfs_fs.h>
#include <linux/errno.h>
@@ -34,9 +37,6 @@
* ***FIXME*** should probably put this in nfs_fs.h */
#define NFS_SLACK_SPACE 1024
-
-extern struct socket *socki_lookup(struct inode *inode);
-
#define _S(nr) (1<<((nr)-1))
/*
@@ -78,7 +78,7 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end, int
file = server->file;
inode = file->f_inode;
select = file->f_op->select;
- sock = socki_lookup(inode);
+ sock = &inode->u.socket_i;
if (!sock) {
printk("nfs_rpc_call: socki_lookup failed\n");
return -EBADF;
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index 4cbe631c6..85c40b495 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -8,6 +8,10 @@
* nfs symlink handling code
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/sched.h>
diff --git a/fs/open.c b/fs/open.c
index ff95d375f..4b47c8408 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -16,10 +16,11 @@
#include <linux/signal.h>
#include <linux/tty.h>
#include <linux/time.h>
+#include <linux/mm.h>
#include <asm/segment.h>
-extern void fcntl_remove_locks(struct task_struct *, struct file *, unsigned int fd);
+extern void locks_remove_locks(struct task_struct *, struct file *);
asmlinkage int sys_ustat(int dev, struct ustat * ubuf)
{
@@ -41,7 +42,7 @@ asmlinkage int sys_statfs(const char * path, struct statfs * buf)
iput(inode);
return -ENOSYS;
}
- inode->i_sb->s_op->statfs(inode->i_sb, buf);
+ inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
iput(inode);
return 0;
}
@@ -61,7 +62,7 @@ asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
return -ENOENT;
if (!inode->i_sb->s_op->statfs)
return -ENOSYS;
- inode->i_sb->s_op->statfs(inode->i_sb, buf);
+ inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
return 0;
}
@@ -74,10 +75,14 @@ asmlinkage int sys_truncate(const char * path, unsigned int length)
error = namei(path,&inode);
if (error)
return error;
- if (S_ISDIR(inode->i_mode) || !permission(inode,MAY_WRITE)) {
+ if (S_ISDIR(inode->i_mode)) {
iput(inode);
return -EACCES;
}
+ if ((error = permission(inode,MAY_WRITE)) != 0) {
+ iput(inode);
+ return error;
+ }
if (IS_RDONLY(inode)) {
iput(inode);
return -EROFS;
@@ -147,14 +152,67 @@ asmlinkage int sys_utime(char * filename, struct utimbuf * times)
}
/* Don't worry, the checks are done in inode_change_ok() */
if (times) {
+ error = verify_area(VERIFY_READ, times, sizeof(*times));
+ if (error) {
+ iput(inode);
+ return error;
+ }
actime = get_fs_long((unsigned long *) &times->actime);
modtime = get_fs_long((unsigned long *) &times->modtime);
newattrs.ia_ctime = CURRENT_TIME;
flags = ATTR_ATIME_SET | ATTR_MTIME_SET;
} else {
- if (!permission(inode,MAY_WRITE)) {
+ if ((error = permission(inode,MAY_WRITE)) != 0) {
iput(inode);
- return -EACCES;
+ return error;
+ }
+ actime = modtime = newattrs.ia_ctime = CURRENT_TIME;
+ }
+ newattrs.ia_atime = actime;
+ newattrs.ia_mtime = modtime;
+ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME | flags;
+ inode->i_dirt = 1;
+ error = notify_change(inode, &newattrs);
+ iput(inode);
+ return error;
+}
+
+/* If times==NULL, set access and modification to current time,
+ * must be owner or have write permission.
+ * Else, update from *times, must be owner or super user.
+ */
+asmlinkage int sys_utimes(char * filename, struct timeval * utimes)
+{
+ struct inode * inode;
+ long actime,modtime;
+ int error;
+ unsigned int flags = 0;
+ struct iattr newattrs;
+
+ error = namei(filename,&inode);
+ if (error)
+ return error;
+ if (IS_RDONLY(inode)) {
+ iput(inode);
+ return -EROFS;
+ }
+ /* Don't worry, the checks are done in inode_change_ok() */
+ if (utimes) {
+ struct timeval times[2];
+ error = verify_area(VERIFY_READ, utimes, sizeof(times));
+ if (error) {
+ iput(inode);
+ return error;
+ }
+ memcpy_fromfs(&times, utimes, sizeof(times));
+ actime = times[0].tv_sec;
+ modtime = times[1].tv_sec;
+ newattrs.ia_ctime = CURRENT_TIME;
+ flags = ATTR_ATIME_SET | ATTR_MTIME_SET;
+ } else {
+ if ((error = permission(inode,MAY_WRITE)) != 0) {
+ iput(inode);
+ return error;
}
actime = modtime = newattrs.ia_ctime = CURRENT_TIME;
}
@@ -185,8 +243,7 @@ asmlinkage int sys_access(const char * filename, int mode)
current->fsgid = current->gid;
res = namei(filename,&inode);
if (!res) {
- if (!permission(inode, mode))
- res = -EACCES;
+ res = permission(inode, mode);
iput(inode);
}
current->fsuid = old_fsuid;
@@ -206,9 +263,9 @@ asmlinkage int sys_chdir(const char * filename)
iput(inode);
return -ENOTDIR;
}
- if (!permission(inode,MAY_EXEC)) {
+ if ((error = permission(inode,MAY_EXEC)) != 0) {
iput(inode);
- return -EACCES;
+ return error;
}
iput(current->fs->pwd);
current->fs->pwd = inode;
@@ -219,6 +276,7 @@ asmlinkage int sys_fchdir(unsigned int fd)
{
struct inode * inode;
struct file * file;
+ int error;
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
return -EBADF;
@@ -226,8 +284,8 @@ asmlinkage int sys_fchdir(unsigned int fd)
return -ENOENT;
if (!S_ISDIR(inode->i_mode))
return -ENOTDIR;
- if (!permission(inode,MAY_EXEC))
- return -EACCES;
+ if ((error = permission(inode,MAY_EXEC)) != 0)
+ return error;
iput(current->fs->pwd);
current->fs->pwd = inode;
inode->i_count++;
@@ -267,6 +325,8 @@ asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
return -ENOENT;
if (IS_RDONLY(inode))
return -EROFS;
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ return -EPERM;
if (mode == (mode_t) -1)
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
@@ -289,6 +349,10 @@ asmlinkage int sys_chmod(const char * filename, mode_t mode)
iput(inode);
return -EROFS;
}
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+ iput(inode);
+ return -EPERM;
+ }
if (mode == (mode_t) -1)
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
@@ -312,6 +376,8 @@ asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
return -ENOENT;
if (IS_RDONLY(inode))
return -EROFS;
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ return -EPERM;
if (user == (uid_t) -1)
user = inode->i_uid;
if (group == (gid_t) -1)
@@ -352,6 +418,10 @@ asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
iput(inode);
return -EROFS;
}
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+ iput(inode);
+ return -EPERM;
+ }
if (user == (uid_t) -1)
user = inode->i_uid;
if (group == (gid_t) -1)
@@ -401,10 +471,10 @@ int do_open(const char * filename,int flags,int mode)
struct file * f;
int flag,error,fd;
- for(fd=0 ; fd<NR_OPEN ; fd++)
+ for(fd=0; fd<NR_OPEN && fd<current->rlim[RLIMIT_NOFILE].rlim_cur; fd++)
if (!current->files->fd[fd])
break;
- if (fd>=NR_OPEN)
+ if (fd>=NR_OPEN || fd>=current->rlim[RLIMIT_NOFILE].rlim_cur)
return -EMFILE;
FD_CLR(fd,&current->files->close_on_exec);
f = get_empty_filp();
@@ -418,8 +488,11 @@ int do_open(const char * filename,int flags,int mode)
if (flag & (O_TRUNC | O_CREAT))
flag |= 2;
error = open_namei(filename,flag,mode,&inode,NULL);
- if (!error && (f->f_mode & 2))
+ if (!error && (f->f_mode & 2)) {
error = get_write_access(inode);
+ if (error)
+ iput(inode);
+ }
if (error) {
current->files->fd[fd]=NULL;
f->f_count--;
@@ -464,7 +537,7 @@ asmlinkage int sys_creat(const char * pathname, int mode)
return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
}
-int close_fp(struct file *filp, unsigned int fd)
+int close_fp(struct file *filp)
{
struct inode *inode;
@@ -474,7 +547,7 @@ int close_fp(struct file *filp, unsigned int fd)
}
inode = filp->f_inode;
if (inode)
- fcntl_remove_locks(current, filp, fd);
+ locks_remove_locks(current, filp);
if (filp->f_count > 1) {
filp->f_count--;
return 0;
@@ -498,7 +571,7 @@ asmlinkage int sys_close(unsigned int fd)
if (!(filp = current->files->fd[fd]))
return -EBADF;
current->files->fd[fd] = NULL;
- return (close_fp (filp, fd));
+ return (close_fp (filp));
}
/*
diff --git a/fs/pipe.c b/fs/pipe.c
index bc557888e..e50c83b21 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -12,6 +12,7 @@
#include <linux/signal.h>
#include <linux/fcntl.h>
#include <linux/termios.h>
+#include <linux/mm.h>
/* We don't use the head/tail construction any more. Now we use the start/len*/
@@ -120,11 +121,6 @@ static int pipe_lseek(struct inode * inode, struct file * file, off_t offset, in
return -ESPIPE;
}
-static int pipe_readdir(struct inode * inode, struct file * file, struct dirent * de, int count)
-{
- return -ENOTDIR;
-}
-
static int bad_pipe_rw(struct inode * inode, struct file * filp, char * buf, int count)
{
return -EBADF;
@@ -137,9 +133,9 @@ static int pipe_ioctl(struct inode *pino, struct file * filp,
switch (cmd) {
case FIONREAD:
- error = verify_area(VERIFY_WRITE, (void *) arg,4);
+ error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
if (!error)
- put_fs_long(PIPE_SIZE(*pino),(unsigned long *) arg);
+ put_fs_long(PIPE_SIZE(*pino),(int *) arg);
return error;
default:
return -EINVAL;
@@ -270,7 +266,7 @@ struct file_operations connecting_fifo_fops = {
pipe_lseek,
connect_read,
bad_pipe_rw,
- pipe_readdir,
+ NULL, /* no readdir */
connect_select,
pipe_ioctl,
NULL, /* no mmap on pipes.. surprise */
@@ -283,7 +279,7 @@ struct file_operations read_fifo_fops = {
pipe_lseek,
pipe_read,
bad_pipe_rw,
- pipe_readdir,
+ NULL, /* no readdir */
fifo_select,
pipe_ioctl,
NULL, /* no mmap on pipes.. surprise */
@@ -296,7 +292,7 @@ struct file_operations write_fifo_fops = {
pipe_lseek,
bad_pipe_rw,
pipe_write,
- pipe_readdir,
+ NULL, /* no readdir */
fifo_select,
pipe_ioctl,
NULL, /* mmap */
@@ -309,7 +305,7 @@ struct file_operations rdwr_fifo_fops = {
pipe_lseek,
pipe_read,
pipe_write,
- pipe_readdir,
+ NULL, /* no readdir */
fifo_select,
pipe_ioctl,
NULL, /* mmap */
@@ -322,7 +318,7 @@ struct file_operations read_pipe_fops = {
pipe_lseek,
pipe_read,
bad_pipe_rw,
- pipe_readdir,
+ NULL, /* no readdir */
pipe_select,
pipe_ioctl,
NULL, /* no mmap on pipes.. surprise */
@@ -335,7 +331,7 @@ struct file_operations write_pipe_fops = {
pipe_lseek,
bad_pipe_rw,
pipe_write,
- pipe_readdir,
+ NULL, /* no readdir */
pipe_select,
pipe_ioctl,
NULL, /* mmap */
@@ -348,7 +344,7 @@ struct file_operations rdwr_pipe_fops = {
pipe_lseek,
pipe_read,
pipe_write,
- pipe_readdir,
+ NULL, /* no readdir */
pipe_select,
pipe_ioctl,
NULL, /* mmap */
@@ -375,43 +371,39 @@ struct inode_operations pipe_inode_operations = {
NULL /* permission */
};
-asmlinkage int sys_pipe(unsigned long * fildes)
+int do_pipe(int *fd)
{
struct inode * inode;
- struct file * f[2];
- int fd[2];
+ struct file *f[2];
int i,j;
- j = verify_area(VERIFY_WRITE,fildes,8);
- if (j)
- return j;
+ inode = get_pipe_inode();
+ if (!inode)
+ return -ENFILE;
+
for(j=0 ; j<2 ; j++)
if (!(f[j] = get_empty_filp()))
break;
- if (j==1)
- f[0]->f_count--;
- if (j<2)
+ if (j < 2) {
+ iput(inode);
+ if (j)
+ f[0]->f_count--;
return -ENFILE;
+ }
j=0;
- for(i=0;j<2 && i<NR_OPEN;i++)
+ for(i=0;j<2 && i<NR_OPEN && i<current->rlim[RLIMIT_NOFILE].rlim_cur;i++)
if (!current->files->fd[i]) {
current->files->fd[ fd[j]=i ] = f[j];
j++;
}
- if (j==1)
- current->files->fd[fd[0]]=NULL;
if (j<2) {
+ iput(inode);
f[0]->f_count--;
f[1]->f_count--;
+ if (j)
+ current->files->fd[fd[0]] = NULL;
return -EMFILE;
}
- if (!(inode=get_pipe_inode())) {
- current->files->fd[fd[0]] = NULL;
- current->files->fd[fd[1]] = NULL;
- f[0]->f_count--;
- f[1]->f_count--;
- return -ENFILE;
- }
f[0]->f_inode = f[1]->f_inode = inode;
f[0]->f_pos = f[1]->f_pos = 0;
f[0]->f_flags = O_RDONLY;
@@ -420,7 +412,5 @@ asmlinkage int sys_pipe(unsigned long * fildes)
f[1]->f_flags = O_WRONLY;
f[1]->f_op = &write_pipe_fops;
f[1]->f_mode = 2; /* write */
- put_fs_long(fd[0],0+fildes);
- put_fs_long(fd[1],1+fildes);
return 0;
}
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 6fd7bccbe..dad91d707 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -13,6 +13,18 @@
* bad '!' which forced address recalculation for
* EVERY character on the current page.
* <middelin@polyware.iaf.nl>
+ *
+ * Danny ter Haar : Some minor additions for cpuinfo
+ * <danny@ow.nl>
+ *
+ * Alessandro Rubini : profile extension.
+ * <rubini@ipvvis.unipv.it>
+ *
+ * Jeff Tranter : added BogoMips field to cpuinfo
+ * <Jeff_Tranter@Mitel.COM>
+ *
+ * Bruno Haible : remove 4K limit for the maps file
+ * <haible@ma2s2.mathematik.uni-karlsruhe.de>
*/
#include <linux/types.h>
@@ -26,8 +38,12 @@
#include <linux/string.h>
#include <linux/mman.h>
#include <linux/proc_fs.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/mm.h>
#include <asm/segment.h>
+#include <asm/pgtable.h>
#include <asm/io.h>
#define LOAD_INT(x) ((x) >> FSHIFT)
@@ -37,6 +53,7 @@
int get_malloc(char * buffer);
#endif
+
static int read_core(struct inode * inode, struct file * file,char * buf, int count)
{
unsigned long p = file->f_pos;
@@ -91,6 +108,66 @@ struct inode_operations proc_kcore_inode_operations = {
&proc_kcore_operations,
};
+
+#ifdef CONFIG_PROFILE
+
+extern unsigned long prof_len;
+extern unsigned long * prof_buffer;
+/*
+ * This function accesses profiling information. The returned data is
+ * binary: the sampling step and the actual contents of the profile
+ * buffer. Use of the program readprofile is recommended in order to
+ * get meaningful info out of these data.
+ */
+static int read_profile(struct inode *inode, struct file *file, char *buf, int count)
+{
+ unsigned long p = file->f_pos;
+ int read;
+ char * pnt;
+ unsigned long sample_step = 1 << CONFIG_PROFILE_SHIFT;
+
+ if (count < 0)
+ return -EINVAL;
+ if (p >= (prof_len+1)*sizeof(unsigned long))
+ return 0;
+ if (count > (prof_len+1)*sizeof(unsigned long) - p)
+ count = (prof_len+1)*sizeof(unsigned long) - p;
+ read = 0;
+
+ while (p < sizeof(unsigned long) && count > 0) {
+ put_fs_byte(*((char *)(&sample_step)+p),buf);
+ buf++; p++; count--; read++;
+ }
+ pnt = (char *)prof_buffer + p - sizeof(unsigned long);
+ memcpy_tofs(buf,(void *)pnt,count);
+ read += count;
+ file->f_pos += read;
+ return read;
+}
+
+/* Writing to /proc/profile resets the counters */
+static int write_profile(struct inode * inode, struct file * file, char * buf, int count)
+{
+ int i=prof_len;
+
+ while (i--)
+ prof_buffer[i]=0UL;
+ return count;
+}
+
+static struct file_operations proc_profile_operations = {
+ NULL, /* lseek */
+ read_profile,
+ write_profile,
+};
+
+struct inode_operations proc_profile_inode_operations = {
+ &proc_profile_operations,
+};
+
+#endif /* CONFIG_PROFILE */
+
+
static int get_loadavg(char * buffer)
{
int a, b, c;
@@ -98,10 +175,11 @@ static int get_loadavg(char * buffer)
a = avenrun[0] + (FIXED_1/200);
b = avenrun[1] + (FIXED_1/200);
c = avenrun[2] + (FIXED_1/200);
- return sprintf(buffer,"%d.%02d %d.%02d %d.%02d\n",
+ return sprintf(buffer,"%d.%02d %d.%02d %d.%02d %d/%d\n",
LOAD_INT(a), LOAD_FRAC(a),
LOAD_INT(b), LOAD_FRAC(b),
- LOAD_INT(c), LOAD_FRAC(c));
+ LOAD_INT(c), LOAD_FRAC(c),
+ nr_running, nr_tasks);
}
static int get_kstat(char * buffer)
@@ -148,11 +226,29 @@ static int get_uptime(char * buffer)
uptime = jiffies;
idle = task[0]->utime + task[0]->stime;
+
+ /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
+ that would overflow about every five days at HZ == 100.
+ Therefore the identity a = (a / b) * b + a % b is used so that it is
+ calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
+ The part in front of the '+' always evaluates as 0 (mod 100). All divisions
+ in the above formulas are truncating. For HZ being a power of 10, the
+ calculations simplify to the version in the #else part (if the printf
+ format is adapted to the same number of digits as zeroes in HZ.
+ */
+#if HZ!=100
+ return sprintf(buffer,"%lu.%02lu %lu.%02lu\n",
+ uptime / HZ,
+ (((uptime % HZ) * 100) / HZ) % 100,
+ idle / HZ,
+ (((idle % HZ) * 100) / HZ) % 100);
+#else
return sprintf(buffer,"%lu.%02lu %lu.%02lu\n",
uptime / HZ,
uptime % HZ,
idle / HZ,
idle % HZ);
+#endif
}
static int get_meminfo(char * buffer)
@@ -188,23 +284,34 @@ static struct task_struct ** get_task(pid_t pid)
return NULL;
}
-static unsigned long get_phys_addr(struct task_struct ** p, unsigned long ptr)
+static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
{
- unsigned long page;
+ pgd_t *page_dir;
+ pmd_t *page_middle;
+ pte_t pte;
- if (!p || !*p || ptr >= TASK_SIZE)
+ if (!p || ptr >= TASK_SIZE)
+ return 0;
+ page_dir = pgd_offset(p,ptr);
+ if (pgd_none(*page_dir))
+ return 0;
+ if (pgd_bad(*page_dir)) {
+ printk("bad page directory entry %08lx\n", pgd_val(*page_dir));
+ pgd_clear(page_dir);
+ return 0;
+ }
+ page_middle = pmd_offset(page_dir,ptr);
+ if (pmd_none(*page_middle))
return 0;
- page = *PAGE_DIR_OFFSET((*p)->tss.cr3,ptr);
- if (!(page & PAGE_PRESENT))
+ if (pmd_bad(*page_middle)) {
+ printk("bad page middle entry %08lx\n", pmd_val(*page_middle));
+ pmd_clear(page_middle);
return 0;
- page &= PAGE_MASK;
- page += PAGE_PTR(ptr);
- page = *(unsigned long *) page;
- if (!(page & PAGE_PRESENT))
+ }
+ pte = *pte_offset(page_middle,ptr);
+ if (!pte_present(pte))
return 0;
- page &= PAGE_MASK;
- page += ptr & ~PAGE_MASK;
- return page;
+ return pte_page(pte) + (ptr & ~PAGE_MASK);
}
static int get_array(struct task_struct ** p, unsigned long start, unsigned long end, char * buffer)
@@ -216,7 +323,7 @@ static int get_array(struct task_struct ** p, unsigned long start, unsigned long
if (start >= end)
return result;
for (;;) {
- addr = get_phys_addr(p, start);
+ addr = get_phys_addr(*p, start);
if (!addr)
goto ready;
do {
@@ -260,6 +367,7 @@ static int get_arg(int pid, char * buffer)
static unsigned long get_wchan(struct task_struct *p)
{
+#ifdef __i386__
unsigned long ebp, eip;
unsigned long stack_page;
int count = 0;
@@ -279,6 +387,7 @@ static unsigned long get_wchan(struct task_struct *p)
return eip;
ebp = *(unsigned long *) ebp;
} while (count++ < 16);
+#endif
return 0;
}
@@ -310,7 +419,7 @@ static int get_stat(int pid, char * buffer)
}
wchan = get_wchan(*p);
for(i=0; i<32; ++i) {
- switch((int) (*p)->sigaction[i].sa_handler) {
+ switch((unsigned long) (*p)->sigaction[i].sa_handler) {
case 1: sigignore |= bit; break;
case 0: break;
default: sigcatch |= bit;
@@ -321,7 +430,7 @@ static int get_stat(int pid, char * buffer)
else
tty_pgrp = -1;
return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
-%lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %u %lu %lu %lu %lu %lu %lu \
+%lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu \
%lu %lu %lu %lu\n",
pid,
(*p)->comm,
@@ -361,83 +470,181 @@ static int get_stat(int pid, char * buffer)
sigcatch,
wchan);
}
+
+static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
+ int * pages, int * shared, int * dirty, int * total)
+{
+ pte_t * pte;
+ unsigned long end;
+
+ if (pmd_none(*pmd))
+ return;
+ if (pmd_bad(*pmd)) {
+ printk("statm_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
+ pmd_clear(pmd);
+ return;
+ }
+ pte = pte_offset(pmd, address);
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ pte_t page = *pte;
+
+ address += PAGE_SIZE;
+ pte++;
+ if (pte_none(page))
+ continue;
+ ++*total;
+ if (!pte_present(page))
+ continue;
+ ++*pages;
+ if (pte_dirty(page))
+ ++*dirty;
+ if (pte_page(page) >= high_memory)
+ continue;
+ if (mem_map[MAP_NR(pte_page(page))] > 1)
+ ++*shared;
+ } while (address < end);
+}
+
+static inline void statm_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size,
+ int * pages, int * shared, int * dirty, int * total)
+{
+ pmd_t * pmd;
+ unsigned long end;
+
+ if (pgd_none(*pgd))
+ return;
+ if (pgd_bad(*pgd)) {
+ printk("statm_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd));
+ pgd_clear(pgd);
+ return;
+ }
+ pmd = pmd_offset(pgd, address);
+ address &= ~PGDIR_MASK;
+ end = address + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ do {
+ statm_pte_range(pmd, address, end - address, pages, shared, dirty, total);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address < end);
+}
+
+static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long end,
+ int * pages, int * shared, int * dirty, int * total)
+{
+ while (address < end) {
+ statm_pmd_range(pgd, address, end - address, pages, shared, dirty, total);
+ address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ pgd++;
+ }
+}
static int get_statm(int pid, char * buffer)
{
struct task_struct ** p = get_task(pid);
- int i, tpag;
int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
- unsigned long ptbl, *buf, *pte, *pagedir, map_nr;
if (!p || !*p)
return 0;
- tpag = (*p)->mm->end_code / PAGE_SIZE;
if ((*p)->state != TASK_ZOMBIE) {
- pagedir = (unsigned long *) (*p)->tss.cr3;
- for (i = 0; i < 0x300; ++i) {
- if ((ptbl = pagedir[i]) == 0) {
- tpag -= PTRS_PER_PAGE;
- continue;
- }
- buf = (unsigned long *)(ptbl & PAGE_MASK);
- for (pte = buf; pte < (buf + PTRS_PER_PAGE); ++pte) {
- if (*pte != 0) {
- ++size;
- if (*pte & 1) {
- ++resident;
- if (tpag > 0)
- ++trs;
- else
- ++drs;
- if (i >= 15 && i < 0x2f0) {
- ++lrs;
- if (*pte & 0x40)
- ++dt;
- else
- --drs;
- }
- map_nr = MAP_NR(*pte);
- if (map_nr < (high_memory / PAGE_SIZE) && mem_map[map_nr] > 1)
- ++share;
+ struct vm_area_struct * vma = (*p)->mm->mmap;
+
+ while (vma) {
+ pgd_t *pgd = pgd_offset(*p, vma->vm_start);
+ int pages = 0, shared = 0, dirty = 0, total = 0;
+
+ statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total);
+ resident += pages;
+ share += shared;
+ dt += dirty;
+ size += total;
+ if (vma->vm_flags & VM_EXECUTABLE)
+ trs += pages; /* text */
+ else if (vma->vm_flags & VM_GROWSDOWN)
+ drs += pages; /* stack */
+ else if (vma->vm_end > 0x60000000)
+ lrs += pages; /* library */
+ else
+ drs += pages;
+ vma = vma->vm_next;
}
- }
- --tpag;
- }
- }
}
return sprintf(buffer,"%d %d %d %d %d %d %d\n",
size, resident, share, trs, lrs, drs, dt);
}
-static int get_maps(int pid, char *buf)
+/*
+ * The way we support synthetic files > 4K
+ * - without storing their contents in some buffer and
+ * - without walking through the entire synthetic file until we reach the
+ * position of the requested data
+ * is to cleverly encode the current position in the file's f_pos field.
+ * There is no requirement that a read() call which returns `count' bytes
+ * of data increases f_pos by exactly `count'.
+ *
+ * This idea is Linus' one. Bruno implemented it.
+ */
+
+/*
+ * For the /proc/<pid>/maps file, we use fixed length records, each containing
+ * a single line.
+ */
+#define MAPS_LINE_LENGTH 1024
+#define MAPS_LINE_SHIFT 10
+/*
+ * f_pos = (number of the vma in the task->mm->mmap list) * MAPS_LINE_LENGTH
+ * + (index into the line)
+ */
+#define MAPS_LINE_FORMAT "%08lx-%08lx %s %08lx %02x:%02x %lu\n"
+#define MAPS_LINE_MAX 49 /* sum of 8 1 8 1 4 1 8 1 2 1 2 1 10 1 */
+
+static int read_maps (int pid, struct file * file, char * buf, int count)
{
- int sz = 0;
- struct task_struct **p = get_task(pid);
- struct vm_area_struct *map;
+ struct task_struct ** p = get_task(pid);
+ char * destptr;
+ loff_t lineno;
+ int column;
+ struct vm_area_struct * map;
+ int i;
if (!p || !*p)
+ return -EINVAL;
+
+ if (count == 0)
return 0;
- for(map = (*p)->mm->mmap; map != NULL; map = map->vm_next) {
- char str[7], *cp = str;
+ /* decode f_pos */
+ lineno = file->f_pos >> MAPS_LINE_SHIFT;
+ column = file->f_pos & (MAPS_LINE_LENGTH-1);
+
+ /* quickly go to line lineno */
+ for (map = (*p)->mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
+ continue;
+
+ destptr = buf;
+
+ for ( ; map ; ) {
+ /* produce the next line */
+ char line[MAPS_LINE_MAX+1];
+ char str[5], *cp = str;
int flags;
- int end = sz + 80; /* Length of line */
dev_t dev;
unsigned long ino;
+ int len;
flags = map->vm_flags;
*cp++ = flags & VM_READ ? 'r' : '-';
*cp++ = flags & VM_WRITE ? 'w' : '-';
*cp++ = flags & VM_EXEC ? 'x' : '-';
- *cp++ = flags & VM_SHARED ? 's' : 'p';
+ *cp++ = flags & VM_MAYSHARE ? 's' : 'p';
*cp++ = 0;
-
- if (end >= PAGE_SIZE) {
- sprintf(buf+sz, "...\n");
- break;
- }
-
+
if (map->vm_inode != NULL) {
dev = map->vm_inode->i_dev;
ino = map->vm_inode->i_ino;
@@ -446,16 +653,44 @@ static int get_maps(int pid, char *buf)
ino = 0;
}
- sz += sprintf(buf+sz, "%08lx-%08lx %s %08lx %02x:%02x %lu\n",
+ len = sprintf(line, MAPS_LINE_FORMAT,
map->vm_start, map->vm_end, str, map->vm_offset,
MAJOR(dev),MINOR(dev), ino);
- if (sz > end) {
- printk("get_maps: end(%d) < sz(%d)\n", end, sz);
- break;
+
+ if (column >= len) {
+ column = 0; /* continue with next line at column 0 */
+ lineno++;
+ map = map->vm_next;
+ continue;
+ }
+
+ i = len-column;
+ if (i > count)
+ i = count;
+ memcpy_tofs(destptr, line+column, i);
+ destptr += i; count -= i;
+ column += i;
+ if (column >= len) {
+ column = 0; /* next time: next line at column 0 */
+ lineno++;
+ map = map->vm_next;
}
+
+ /* done? */
+ if (count == 0)
+ break;
+
+ /* By writing to user space, we might have slept.
+ * Stop the loop, to avoid a race condition.
+ */
+ if (*p != current)
+ break;
}
-
- return sz;
+
+ /* encode f_pos */
+ file->f_pos = (lineno << MAPS_LINE_SHIFT) + column;
+
+ return destptr-buf;
}
extern int get_module_list(char *);
@@ -464,6 +699,8 @@ extern int get_filesystem_list(char *);
extern int get_ksyms_list(char *);
extern int get_irq_list(char *);
extern int get_dma_list(char *);
+extern int get_cpuinfo(char *);
+extern int get_pci_list(char*);
static int get_root_array(char * page, int type)
{
@@ -477,6 +714,14 @@ static int get_root_array(char * page, int type)
case PROC_MEMINFO:
return get_meminfo(page);
+#ifdef CONFIG_PCI
+ case PROC_PCI:
+ return get_pci_list(page);
+#endif
+
+ case PROC_CPUINFO:
+ return get_cpuinfo(page);
+
case PROC_VERSION:
return get_version(page);
@@ -505,6 +750,9 @@ static int get_root_array(char * page, int type)
case PROC_DMA:
return get_dma_list(page);
+
+ case PROC_IOPORTS:
+ return get_ioport_list(page);
}
return -EBADF;
}
@@ -520,8 +768,6 @@ static int get_process_array(char * page, int pid, int type)
return get_stat(pid, page);
case PROC_PID_STATM:
return get_statm(pid, page);
- case PROC_PID_MAPS:
- return get_maps(pid, page);
}
return -EBADF;
}
@@ -596,3 +842,49 @@ struct inode_operations proc_array_inode_operations = {
NULL, /* truncate */
NULL /* permission */
};
+
+static int arraylong_read (struct inode * inode, struct file * file, char * buf, int count)
+{
+ unsigned int pid = inode->i_ino >> 16;
+ unsigned int type = inode->i_ino & 0x0000ffff;
+
+ if (count < 0)
+ return -EINVAL;
+
+ switch (type) {
+ case PROC_PID_MAPS:
+ return read_maps(pid, file, buf, count);
+ }
+ return -EINVAL;
+}
+
+static struct file_operations proc_arraylong_operations = {
+ NULL, /* array_lseek */
+ arraylong_read,
+ NULL, /* array_write */
+ NULL, /* array_readdir */
+ NULL, /* array_select */
+ NULL, /* array_ioctl */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ NULL /* can't fsync */
+};
+
+struct inode_operations proc_arraylong_inode_operations = {
+ &proc_arraylong_operations, /* default base directory file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 3dcf0189b..25dd82fe9 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -13,7 +13,7 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
-static int proc_readbase(struct inode *, struct file *, struct dirent *, int);
+static int proc_readbase(struct inode *, struct file *, void *, filldir_t);
static int proc_lookupbase(struct inode *,const char *,int,struct inode **);
static struct file_operations proc_base_operations = {
@@ -121,11 +121,11 @@ static int proc_lookupbase(struct inode * dir,const char * name, int len,
}
static int proc_readbase(struct inode * inode, struct file * filp,
- struct dirent * dirent, int count)
+ void * dirent, filldir_t filldir)
{
struct proc_dir_entry * de;
unsigned int pid, ino;
- int i,j;
+ int i;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
@@ -136,20 +136,14 @@ static int proc_readbase(struct inode * inode, struct file * filp,
break;
if (!pid || i >= NR_TASKS)
return 0;
- if (((unsigned) filp->f_pos) < NR_BASE_DIRENTRY) {
+ while (((unsigned) filp->f_pos) < NR_BASE_DIRENTRY) {
de = base_dir + filp->f_pos;
- filp->f_pos++;
- i = de->namelen;
ino = de->low_ino;
if (ino != 1)
ino |= (pid << 16);
- put_fs_long(ino, &dirent->d_ino);
- put_fs_word(i,&dirent->d_reclen);
- put_fs_byte(0,i+dirent->d_name);
- j = i;
- while (i--)
- put_fs_byte(de->name[i], i+dirent->d_name);
- return j;
+ if (filldir(dirent, de->name, de->namelen, filp->f_pos, ino) < 0)
+ break;
+ filp->f_pos++;
}
return 0;
}
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 954540871..03a20b441 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -13,7 +13,7 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
-static int proc_readfd(struct inode *, struct file *, struct dirent *, int);
+static int proc_readfd(struct inode *, struct file *, void *, filldir_t);
static int proc_lookupfd(struct inode *,const char *,int,struct inode **);
static struct file_operations proc_fd_operations = {
@@ -62,11 +62,10 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len,
ino = dir->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
- ino -= 7;
if (!dir)
return -ENOENT;
sb = dir->i_sb;
- if (!pid || ino || !S_ISDIR(dir->i_mode)) {
+ if (!pid || ino != PROC_PID_FD || !S_ISDIR(dir->i_mode)) {
iput(dir);
return -ENOENT;
}
@@ -76,7 +75,7 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len,
*result = dir;
return 0;
}
- if (!(*result = iget(sb,(pid << 16)+2))) {
+ if (!(*result = iget(sb,(pid << 16)+PROC_PID_INO))) {
iput(dir);
return -ENOENT;
}
@@ -108,73 +107,67 @@ static int proc_lookupfd(struct inode * dir,const char * name, int len,
if (fd >= NR_OPEN || !p->files->fd[fd] || !p->files->fd[fd]->f_inode)
return -ENOENT;
- ino = (pid << 16) + 0x100 + fd;
+ ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
if (!(*result = iget(sb,ino)))
return -ENOENT;
return 0;
}
+#define NUMBUF 10
+
static int proc_readfd(struct inode * inode, struct file * filp,
- struct dirent * dirent, int count)
+ void * dirent, filldir_t filldir)
{
+ char buf[NUMBUF];
+ int task_nr;
struct task_struct * p;
unsigned int fd, pid, ino;
- int i,j;
+ unsigned long i,j;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
ino = inode->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
- ino -= 7;
- if (ino)
+ if (ino != PROC_PID_FD)
return 0;
- while (1) {
- fd = filp->f_pos;
- filp->f_pos++;
- if (fd < 2) {
- i = j = fd+1;
- if (!fd)
- fd = inode->i_ino;
- else
- fd = (inode->i_ino & 0xffff0000) | 2;
- put_fs_long(fd, &dirent->d_ino);
- put_fs_word(i, &dirent->d_reclen);
- put_fs_byte(0, i+dirent->d_name);
- while (i--)
- put_fs_byte('.', i+dirent->d_name);
- return j;
- }
- fd -= 2;
- for (i = 1 ; i < NR_TASKS ; i++)
- if ((p = task[i]) && p->pid == pid)
- break;
- if (i >= NR_TASKS)
+
+ for (fd = filp->f_pos; fd < 2; fd++, filp->f_pos++) {
+ unsigned long ino = inode->i_ino;
+ if (fd)
+ ino = (ino & 0xffff0000) | PROC_PID_INO;
+ if (filldir(dirent, "..", fd+1, fd, ino) < 0)
+ return 0;
+ }
+
+ task_nr = 1;
+ for (;;) {
+ if ((p = task[task_nr]) && p->pid == pid)
+ break;
+ if (++task_nr >= NR_TASKS)
return 0;
- if (fd >= NR_OPEN)
- break;
+ }
+ for (fd -= 2 ; fd < NR_OPEN; fd++, filp->f_pos++) {
if (!p->files->fd[fd] || !p->files->fd[fd]->f_inode)
- continue;
+ continue;
- j = 10;
- i = 1;
- while (fd >= j) {
- j *= 10;
- i++;
- }
- j = i;
- ino = (pid << 16) + 0x100 + fd;
-
- put_fs_long(ino, &dirent->d_ino);
- put_fs_word(i, &dirent->d_reclen);
- put_fs_byte(0, i+dirent->d_name);
- while (i--) {
- put_fs_byte('0'+(fd % 10), i+dirent->d_name);
- fd /= 10;
- }
- return j;
+ j = NUMBUF;
+ i = fd;
+ do {
+ j--;
+ buf[j] = '0' + (i % 10);
+ i /= 10;
+ } while (i);
+
+ ino = (pid << 16) + (PROC_PID_FD_DIR << 8) + fd;
+ if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino) < 0)
+ break;
+
+ /* filldir() migth have slept, so we must re-validate "p" */
+ if (p != task[task_nr] || p->pid != pid)
+ break;
}
return 0;
}
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 0d0848b33..98368730e 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -12,10 +12,13 @@
#include <linux/stat.h>
#include <linux/locks.h>
#include <linux/limits.h>
+#include <linux/config.h>
#include <asm/system.h>
#include <asm/segment.h>
+extern unsigned long prof_len;
+
void proc_put_inode(struct inode *inode)
{
if (inode->i_nlink)
@@ -41,6 +44,37 @@ static struct super_operations proc_sops = {
NULL
};
+
+static int parse_options(char *options,uid_t *uid,gid_t *gid)
+{
+ char *this_char,*value;
+
+ *uid = current->uid;
+ *gid = current->gid;
+ if (!options) return 1;
+ for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+ if ((value = strchr(this_char,'=')) != NULL)
+ *value++ = 0;
+ if (!strcmp(this_char,"uid")) {
+ if (!value || !*value)
+ return 0;
+ *uid = simple_strtoul(value,&value,0);
+ if (*value)
+ return 0;
+ }
+ else if (!strcmp(this_char,"gid")) {
+ if (!value || !*value)
+ return 0;
+ *gid = simple_strtoul(value,&value,0);
+ if (*value)
+ return 0;
+ }
+ else return 0;
+ }
+ return 1;
+}
+
+
struct super_block *proc_read_super(struct super_block *s,void *data,
int silent)
{
@@ -55,20 +89,23 @@ struct super_block *proc_read_super(struct super_block *s,void *data,
printk("get root inode failed\n");
return NULL;
}
+ parse_options(data, &s->s_mounted->i_uid, &s->s_mounted->i_gid);
return s;
}
-void proc_statfs(struct super_block *sb, struct statfs *buf)
+void proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
- put_fs_long(PROC_SUPER_MAGIC, &buf->f_type);
- put_fs_long(PAGE_SIZE/sizeof(long), &buf->f_bsize);
- put_fs_long(0, &buf->f_blocks);
- put_fs_long(0, &buf->f_bfree);
- put_fs_long(0, &buf->f_bavail);
- put_fs_long(0, &buf->f_files);
- put_fs_long(0, &buf->f_ffree);
- put_fs_long(NAME_MAX, &buf->f_namelen);
- /* Don't know what value to put in buf->f_fsid */
+ struct statfs tmp;
+
+ tmp.f_type = PROC_SUPER_MAGIC;
+ tmp.f_bsize = PAGE_SIZE/sizeof(long);
+ tmp.f_blocks = 0;
+ tmp.f_bfree = 0;
+ tmp.f_bavail = 0;
+ tmp.f_files = 0;
+ tmp.f_ffree = 0;
+ tmp.f_namelen = NAME_MAX;
+ memcpy_tofs(buf, &tmp, bufsiz);
}
void proc_read_inode(struct inode * inode)
@@ -104,7 +141,24 @@ void proc_read_inode(struct inode * inode)
return;
}
- /* files within /proc/net */
+#ifdef CONFIG_IP_ACCT
+ /* this file may be opened R/W by root to reset the accounting */
+ if (ino == PROC_NET_IPACCT) {
+ inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
+ inode->i_op = &proc_net_inode_operations;
+ return;
+ }
+#endif
+#ifdef CONFIG_IP_FIREWALL
+ /* these files may be opened R/W by root to reset the counters */
+ if ((ino == PROC_NET_IPFWFWD) || (ino == PROC_NET_IPFWBLK)) {
+ inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
+ inode->i_op = &proc_net_inode_operations;
+ return;
+ }
+#endif
+
+ /* other files within /proc/net */
if ((ino >= PROC_NET_UNIX) && (ino < PROC_NET_LAST)) {
inode->i_mode = S_IFREG | S_IRUGO;
inode->i_op = &proc_net_inode_operations;
@@ -114,7 +168,7 @@ void proc_read_inode(struct inode * inode)
if (!pid) {
switch (ino) {
case PROC_KMSG:
- inode->i_mode = S_IFREG | S_IRUGO;
+ inode->i_mode = S_IFREG | S_IRUSR;
inode->i_op = &proc_kmsg_inode_operations;
break;
case PROC_NET:
@@ -127,6 +181,13 @@ void proc_read_inode(struct inode * inode)
inode->i_op = &proc_kcore_inode_operations;
inode->i_size = high_memory + PAGE_SIZE;
break;
+#ifdef CONFIG_PROFILE
+ case PROC_PROFILE:
+ inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
+ inode->i_op = &proc_profile_inode_operations;
+ inode->i_size = (1+prof_len) * sizeof(unsigned long);
+ break;
+#endif
default:
inode->i_mode = S_IFREG | S_IRUGO;
inode->i_op = &proc_array_inode_operations;
@@ -160,13 +221,19 @@ void proc_read_inode(struct inode * inode)
inode->i_nlink = 2;
return;
case PROC_PID_ENVIRON:
+ inode->i_mode = S_IFREG | S_IRUSR;
+ inode->i_op = &proc_array_inode_operations;
+ return;
case PROC_PID_CMDLINE:
case PROC_PID_STAT:
case PROC_PID_STATM:
- case PROC_PID_MAPS:
inode->i_mode = S_IFREG | S_IRUGO;
inode->i_op = &proc_array_inode_operations;
return;
+ case PROC_PID_MAPS:
+ inode->i_mode = S_IFIFO | S_IRUGO;
+ inode->i_op = &proc_arraylong_inode_operations;
+ return;
}
switch (ino >> 8) {
case PROC_PID_FD_DIR:
diff --git a/fs/proc/link.c b/fs/proc/link.c
index 769014f46..2f940a275 100644
--- a/fs/proc/link.c
+++ b/fs/proc/link.c
@@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/fs.h>
+#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
@@ -103,16 +104,16 @@ static int proc_follow_link(struct inode * dir, struct inode * inode,
unsigned int pid, ino;
struct task_struct * p;
struct inode * new_inode;
- int i;
+ int i, error;
*res_inode = NULL;
if (dir)
iput(dir);
if (!inode)
return -ENOENT;
- if (!permission(inode, MAY_EXEC)) {
+ if ((error = permission(inode, MAY_EXEC)) != 0){
iput(inode);
- return -EACCES;
+ return error;
}
ino = inode->i_ino;
pid = ino >> 16;
diff --git a/fs/proc/mem.c b/fs/proc/mem.c
index ae043bb0a..f44bd7fbc 100644
--- a/fs/proc/mem.c
+++ b/fs/proc/mem.c
@@ -13,6 +13,7 @@
#include <asm/page.h>
#include <asm/segment.h>
#include <asm/io.h>
+#include <asm/pgtable.h>
/*
* mem_write isn't really a good idea right now. It needs
@@ -24,42 +25,56 @@
static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
{
- unsigned long addr, pid, cr3;
+ pgd_t *page_dir;
+ pmd_t *page_middle;
+ pte_t pte;
+ char * page;
+ struct task_struct * tsk;
+ unsigned long addr, pid;
char *tmp;
- unsigned long pte, page;
int i;
if (count < 0)
return -EINVAL;
pid = inode->i_ino;
pid >>= 16;
- cr3 = 0;
+ tsk = NULL;
for (i = 1 ; i < NR_TASKS ; i++)
if (task[i] && task[i]->pid == pid) {
- cr3 = task[i]->tss.cr3;
+ tsk = task[i];
break;
}
- if (!cr3)
+ if (!tsk)
return -EACCES;
addr = file->f_pos;
tmp = buf;
while (count > 0) {
if (current->signal & ~current->blocked)
break;
- pte = *PAGE_DIR_OFFSET(cr3,addr);
- if (!(pte & PAGE_PRESENT))
+ page_dir = pgd_offset(tsk,addr);
+ if (pgd_none(*page_dir))
break;
- pte &= PAGE_MASK;
- pte += PAGE_PTR(addr);
- page = *(unsigned long *) pte;
- if (!(page & 1))
+ if (pgd_bad(*page_dir)) {
+ printk("Bad page dir entry %08lx\n", pgd_val(*page_dir));
+ pgd_clear(page_dir);
break;
- page &= PAGE_MASK;
- page += addr & ~PAGE_MASK;
+ }
+ page_middle = pmd_offset(page_dir,addr);
+ if (pmd_none(*page_middle))
+ break;
+ if (pmd_bad(*page_middle)) {
+ printk("Bad page middle entry %08lx\n", pmd_val(*page_middle));
+ pmd_clear(page_middle);
+ break;
+ }
+ pte = *pte_offset(page_middle,addr);
+ if (!pte_present(pte))
+ break;
+ page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
i = PAGE_SIZE-(addr & ~PAGE_MASK);
if (i > count)
i = count;
- memcpy_tofs(tmp,(void *) page,i);
+ memcpy_tofs(tmp, page, i);
addr += i;
tmp += i;
count -= i;
@@ -72,9 +87,13 @@ static int mem_read(struct inode * inode, struct file * file,char * buf, int cou
static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
{
- unsigned long addr, pid, cr3;
+ pgd_t *page_dir;
+ pmd_t *page_middle;
+ pte_t pte;
+ char * page;
+ struct task_struct * tsk;
+ unsigned long addr, pid;
char *tmp;
- unsigned long pte, page;
int i;
if (count < 0)
@@ -82,36 +101,44 @@ static int mem_write(struct inode * inode, struct file * file,char * buf, int co
addr = file->f_pos;
pid = inode->i_ino;
pid >>= 16;
- cr3 = 0;
+ tsk = NULL;
for (i = 1 ; i < NR_TASKS ; i++)
if (task[i] && task[i]->pid == pid) {
- cr3 = task[i]->tss.cr3;
+ tsk = task[i];
break;
}
- if (!cr3)
+ if (!tsk)
return -EACCES;
tmp = buf;
while (count > 0) {
if (current->signal & ~current->blocked)
break;
- pte = *PAGE_DIR_OFFSET(cr3,addr);
- if (!(pte & PAGE_PRESENT))
+ page_dir = pgd_offset(tsk,addr);
+ if (pgd_none(*page_dir))
+ break;
+ if (pgd_bad(*page_dir)) {
+ printk("Bad page dir entry %08lx\n", pgd_val(*page_dir));
+ pgd_clear(page_dir);
+ break;
+ }
+ page_middle = pmd_offset(page_dir,addr);
+ if (pmd_none(*page_middle))
break;
- pte &= PAGE_MASK;
- pte += PAGE_PTR(addr);
- page = *(unsigned long *) pte;
- if (!(page & PAGE_PRESENT))
+ if (pmd_bad(*page_middle)) {
+ printk("Bad page middle entry %08lx\n", pmd_val(*page_middle));
+ pmd_clear(page_middle);
break;
- if (!(page & 2)) {
- do_wp_page(0,addr,current,0);
- continue;
}
- page &= PAGE_MASK;
- page += addr & ~PAGE_MASK;
+ pte = *pte_offset(page_middle,addr);
+ if (!pte_present(pte))
+ break;
+ if (!pte_write(pte))
+ break;
+ page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
i = PAGE_SIZE-(addr & ~PAGE_MASK);
if (i > count)
i = count;
- memcpy_fromfs((void *) page,tmp,i);
+ memcpy_fromfs(page, tmp, i);
addr += i;
tmp += i;
count -= i;
@@ -140,92 +167,108 @@ static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int
}
}
-int
-mem_mmap(struct inode * inode, struct file * file,
+/*
+ * This isn't really reliable by any means..
+ */
+int mem_mmap(struct inode * inode, struct file * file,
struct vm_area_struct * vma)
{
- unsigned long *src_table, *dest_table, stmp, dtmp, cr3;
- struct vm_area_struct *src_vma = 0;
- int i;
-
- /* Get the source's task information */
+ struct task_struct *tsk;
+ pgd_t *src_dir, *dest_dir;
+ pmd_t *src_middle, *dest_middle;
+ pte_t *src_table, *dest_table;
+ unsigned long stmp, dtmp;
+ struct vm_area_struct *src_vma = NULL;
+ int i;
- cr3 = 0;
- for (i = 1 ; i < NR_TASKS ; i++)
- if (task[i] && task[i]->pid == (inode->i_ino >> 16)) {
- cr3 = task[i]->tss.cr3;
- src_vma = task[i]->mm->mmap;
- break;
- }
+ /* Get the source's task information */
- if (!cr3)
- return -EACCES;
+ tsk = NULL;
+ for (i = 1 ; i < NR_TASKS ; i++)
+ if (task[i] && task[i]->pid == (inode->i_ino >> 16)) {
+ tsk = task[i];
+ break;
+ }
-/* Ensure that we have a valid source area. (Has to be mmap'ed and
- have valid page information.) We can't map shared memory at the
- moment because working out the vm_area_struct & nattach stuff isn't
- worth it. */
+ if (!tsk)
+ return -EACCES;
- stmp = vma->vm_offset;
- while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) {
- while (src_vma && stmp > src_vma->vm_end)
- src_vma = src_vma->vm_next;
- if (!src_vma || (src_vma->vm_flags & VM_SHM))
- return -EINVAL;
+ /* Ensure that we have a valid source area. (Has to be mmap'ed and
+ have valid page information.) We can't map shared memory at the
+ moment because working out the vm_area_struct & nattach stuff isn't
+ worth it. */
- src_table = PAGE_DIR_OFFSET(cr3, stmp);
- if (!*src_table)
- return -EINVAL;
- src_table = (unsigned long *)((*src_table & PAGE_MASK) + PAGE_PTR(stmp));
- if (!*src_table)
- return -EINVAL;
+ src_vma = tsk->mm->mmap;
+ stmp = vma->vm_offset;
+ while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) {
+ while (src_vma && stmp > src_vma->vm_end)
+ src_vma = src_vma->vm_next;
+ if (!src_vma || (src_vma->vm_flags & VM_SHM))
+ return -EINVAL;
- if (stmp < src_vma->vm_start) {
- if (!(src_vma->vm_flags & VM_GROWSDOWN))
- return -EINVAL;
- if (src_vma->vm_end - stmp > current->rlim[RLIMIT_STACK].rlim_cur)
- return -EINVAL;
- }
- stmp += PAGE_SIZE;
- }
+ src_dir = pgd_offset(tsk, stmp);
+ if (pgd_none(*src_dir))
+ return -EINVAL;
+ if (pgd_bad(*src_dir)) {
+ printk("Bad source page dir entry %08lx\n", pgd_val(*src_dir));
+ return -EINVAL;
+ }
+ src_middle = pmd_offset(src_dir, stmp);
+ if (pmd_none(*src_middle))
+ return -EINVAL;
+ if (pmd_bad(*src_middle)) {
+ printk("Bad source page middle entry %08lx\n", pmd_val(*src_middle));
+ return -EINVAL;
+ }
+ src_table = pte_offset(src_middle, stmp);
+ if (pte_none(*src_table))
+ return -EINVAL;
- src_vma = task[i]->mm->mmap;
- stmp = vma->vm_offset;
- dtmp = vma->vm_start;
+ if (stmp < src_vma->vm_start) {
+ if (!(src_vma->vm_flags & VM_GROWSDOWN))
+ return -EINVAL;
+ if (src_vma->vm_end - stmp > current->rlim[RLIMIT_STACK].rlim_cur)
+ return -EINVAL;
+ }
+ stmp += PAGE_SIZE;
+ }
- while (dtmp < vma->vm_end) {
- while (src_vma && stmp > src_vma->vm_end)
- src_vma = src_vma->vm_next;
+ src_vma = tsk->mm->mmap;
+ stmp = vma->vm_offset;
+ dtmp = vma->vm_start;
- src_table = PAGE_DIR_OFFSET(cr3, stmp);
- src_table = (unsigned long *)((*src_table & PAGE_MASK) + PAGE_PTR(stmp));
+ while (dtmp < vma->vm_end) {
+ while (src_vma && stmp > src_vma->vm_end)
+ src_vma = src_vma->vm_next;
- dest_table = PAGE_DIR_OFFSET(current->tss.cr3, dtmp);
+ src_dir = pgd_offset(tsk, stmp);
+ src_middle = pmd_offset(src_dir, stmp);
+ src_table = pte_offset(src_middle, stmp);
- if (!*dest_table) {
- *dest_table = get_free_page(GFP_KERNEL);
- if (!*dest_table) { oom(current); *dest_table=BAD_PAGE; }
- else *dest_table |= PAGE_TABLE;
- }
-
- dest_table = (unsigned long *)((*dest_table & PAGE_MASK) + PAGE_PTR(dtmp));
+ dest_dir = pgd_offset(current, dtmp);
+ dest_middle = pmd_alloc(dest_dir, dtmp);
+ if (!dest_middle)
+ return -ENOMEM;
+ dest_table = pte_alloc(dest_middle, dtmp);
+ if (!dest_table)
+ return -ENOMEM;
- if (!(*src_table & PAGE_PRESENT))
- do_no_page(src_vma, stmp, PAGE_PRESENT);
+ if (!pte_present(*src_table))
+ do_no_page(src_vma, stmp, 1);
- if ((vma->vm_flags & VM_WRITE) && !(*src_table & PAGE_RW))
- do_wp_page(src_vma, stmp, PAGE_RW | PAGE_PRESENT);
+ if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table))
+ do_wp_page(src_vma, stmp, 1);
- *src_table |= PAGE_DIRTY;
- *dest_table = *src_table;
- mem_map[MAP_NR(*src_table)]++;
+ *src_table = pte_mkdirty(*src_table);
+ *dest_table = *src_table;
+ mem_map[MAP_NR(pte_page(*src_table))]++;
- stmp += PAGE_SIZE;
- dtmp += PAGE_SIZE;
- }
+ stmp += PAGE_SIZE;
+ dtmp += PAGE_SIZE;
+ }
- invalidate();
- return 0;
+ invalidate();
+ return 0;
}
static struct file_operations proc_mem_operations = {
diff --git a/fs/proc/net.c b/fs/proc/net.c
index 601f590d3..7ea4d0634 100644
--- a/fs/proc/net.c
+++ b/fs/proc/net.c
@@ -19,6 +19,8 @@
* Dusted off the code and added IPX. Fixed the 4K limit.
* Erik Schoenfelder (schoenfr@ibr.cs.tu-bs.de)
* /proc/net/snmp.
+ * Alan Cox (gw4pts@gw4pts.ampr.org) 1/95
+ * Added Appletalk slots
*
* proc net directory handling functions
*/
@@ -30,12 +32,15 @@
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/config.h>
+#include <linux/mm.h>
/* forward references */
static int proc_readnet(struct inode * inode, struct file * file,
char * buf, int count);
static int proc_readnetdir(struct inode *, struct file *,
- struct dirent *, int);
+ void *, filldir_t filldir);
static int proc_lookupnet(struct inode *,const char *,int,struct inode **);
/* the get_*_info() functions are in the net code, and are configured
@@ -50,10 +55,24 @@ extern int rarp_get_info(char *, char **, off_t, int);
extern int dev_get_info(char *, char **, off_t, int);
extern int rt_get_info(char *, char **, off_t, int);
extern int snmp_get_info(char *, char **, off_t, int);
+extern int afinet_get_info(char *, char **, off_t, int);
+#if defined(CONFIG_WAVELAN)
+extern int wavelan_get_info(char *, char **, off_t, int);
+#endif /* defined(CONFIG_WAVELAN) */
+#ifdef CONFIG_IP_ACCT
+extern int ip_acct_procinfo(char *, char **, off_t, int, int);
+#endif /* CONFIG_IP_ACCT */
+#ifdef CONFIG_IP_FIREWALL
+extern int ip_fw_blk_procinfo(char *, char **, off_t, int, int);
+extern int ip_fw_fwd_procinfo(char *, char **, off_t, int, int);
+#endif /* CONFIG_IP_FIREWALL */
+extern int ip_msqhst_procinfo(char *, char **, off_t, int);
+extern int ip_mc_procinfo(char *, char **, off_t, int);
#endif /* CONFIG_INET */
#ifdef CONFIG_IPX
extern int ipx_get_info(char *, char **, off_t, int);
extern int ipx_rt_get_info(char *, char **, off_t, int);
+extern int ipx_get_interface_info(char *, char **, off_t , int);
#endif /* CONFIG_IPX */
#ifdef CONFIG_AX25
extern int ax25_get_info(char *, char **, off_t, int);
@@ -64,6 +83,11 @@ extern int nr_nodes_get_info(char *, char **, off_t, int);
extern int nr_neigh_get_info(char *, char **, off_t, int);
#endif /* CONFIG_NETROM */
#endif /* CONFIG_AX25 */
+#ifdef CONFIG_ATALK
+extern int atalk_get_info(char *, char **, off_t, int);
+extern int atalk_rt_get_info(char *, char **, off_t, int);
+extern int atalk_if_get_info(char *, char **, off_t, int);
+#endif
static struct file_operations proc_net_operations = {
@@ -112,13 +136,31 @@ static struct proc_dir_entry net_dir[] = {
{ PROC_NET_TCP, 3, "tcp" },
{ PROC_NET_UDP, 3, "udp" },
{ PROC_NET_SNMP, 4, "snmp" },
+ { PROC_NET_SOCKSTAT, 8, "sockstat" },
#ifdef CONFIG_INET_RARP
{ PROC_NET_RARP, 4, "rarp"},
#endif
+#ifdef CONFIG_IP_MULTICAST
+ { PROC_NET_IGMP, 4, "igmp"},
+#endif
+#ifdef CONFIG_IP_FIREWALL
+ { PROC_NET_IPFWFWD, 10, "ip_forward"},
+ { PROC_NET_IPFWBLK, 8, "ip_block"},
+#endif
+#ifdef CONFIG_IP_MASQUERADE
+ { PROC_NET_IPMSQHST, 13, "ip_masquerade"},
+#endif
+#ifdef CONFIG_IP_ACCT
+ { PROC_NET_IPACCT, 7, "ip_acct"},
+#endif
+#if defined(CONFIG_WAVELAN)
+ { PROC_NET_WAVELAN, 7, "wavelan" },
+#endif /* defined(CONFIG_WAVELAN) */
#endif /* CONFIG_INET */
#ifdef CONFIG_IPX
{ PROC_NET_IPX_ROUTE, 9, "ipx_route" },
{ PROC_NET_IPX, 3, "ipx" },
+ { PROC_NET_IPX_INTERFACE, 13, "ipx_interface" },
#endif /* CONFIG_IPX */
#ifdef CONFIG_AX25
{ PROC_NET_AX25_ROUTE, 10, "ax25_route" },
@@ -129,6 +171,11 @@ static struct proc_dir_entry net_dir[] = {
{ PROC_NET_NR, 2, "nr" },
#endif /* CONFIG_NETROM */
#endif /* CONFIG_AX25 */
+#ifdef CONFIG_ATALK
+ { PROC_NET_ATALK, 9, "appletalk" },
+ { PROC_NET_AT_ROUTE, 11,"atalk_route" },
+ { PROC_NET_ATIF, 11,"atalk_iface" },
+#endif /* CONFIG_ATALK */
{ 0, 0, NULL }
};
@@ -155,31 +202,24 @@ static int proc_lookupnet(struct inode * dir,const char * name, int len,
return -ENOENT;
return 0;
}
+ iput(dir);
return -ENOENT;
}
static int proc_readnetdir(struct inode * inode, struct file * filp,
- struct dirent * dirent, int count)
+ void * dirent, filldir_t filldir)
{
struct proc_dir_entry * de;
unsigned int ino;
- int i,j;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
ino = inode->i_ino;
- if (((unsigned) filp->f_pos) < NR_NET_DIRENTRY) {
+ while (((unsigned) filp->f_pos) < NR_NET_DIRENTRY) {
de = net_dir + filp->f_pos;
+ if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino) < 0)
+ break;
filp->f_pos++;
- i = de->namelen;
- ino = de->low_ino;
- put_fs_long(ino, &dirent->d_ino);
- put_fs_word(i,&dirent->d_reclen);
- put_fs_byte(0,i+dirent->d_name);
- j = i;
- while (i--)
- put_fs_byte(de->name[i], i+dirent->d_name);
- return j;
}
return 0;
}
@@ -216,6 +256,9 @@ static int proc_readnet(struct inode * inode, struct file * file,
length = unix_get_info(page,&start,file->f_pos,thistime);
break;
#ifdef CONFIG_INET
+ case PROC_NET_SOCKSTAT:
+ length = afinet_get_info(page,&start,file->f_pos,thistime);
+ break;
case PROC_NET_ARP:
length = arp_get_info(page,&start,file->f_pos,thistime);
break;
@@ -237,13 +280,47 @@ static int proc_readnet(struct inode * inode, struct file * file,
case PROC_NET_SNMP:
length = snmp_get_info(page, &start, file->f_pos,thistime);
break;
+#ifdef CONFIG_IP_MULTICAST
+ case PROC_NET_IGMP:
+ length = ip_mc_procinfo(page, &start, file->f_pos,thistime);
+ break;
+#endif
+#ifdef CONFIG_IP_FIREWALL
+ case PROC_NET_IPFWFWD:
+ length = ip_fw_fwd_procinfo(page, &start, file->f_pos,
+ thistime, (file->f_flags & O_ACCMODE) == O_RDWR);
+ break;
+ case PROC_NET_IPFWBLK:
+ length = ip_fw_blk_procinfo(page, &start, file->f_pos,
+ thistime, (file->f_flags & O_ACCMODE) == O_RDWR);
+ break;
+#endif
+#ifdef CONFIG_IP_ACCT
+ case PROC_NET_IPACCT:
+ length = ip_acct_procinfo(page, &start, file->f_pos,
+ thistime, (file->f_flags & O_ACCMODE) == O_RDWR);
+ break;
+#endif
+#ifdef CONFIG_IP_MASQUERADE
+ case PROC_NET_IPMSQHST:
+ length = ip_msqhst_procinfo(page, &start, file->f_pos,thistime);
+ break;
+#endif
#ifdef CONFIG_INET_RARP
case PROC_NET_RARP:
length = rarp_get_info(page,&start,file->f_pos,thistime);
break;
#endif /* CONFIG_INET_RARP */
+#if defined(CONFIG_WAVELAN)
+ case PROC_NET_WAVELAN:
+ length = wavelan_get_info(page, &start, file->f_pos, thistime);
+ break;
+#endif /* defined(CONFIG_WAVELAN) */
#endif /* CONFIG_INET */
#ifdef CONFIG_IPX
+ case PROC_NET_IPX_INTERFACE:
+ length = ipx_get_interface_info(page, &start, file->f_pos, thistime);
+ break;
case PROC_NET_IPX_ROUTE:
length = ipx_rt_get_info(page,&start,file->f_pos,thistime);
break;
@@ -251,6 +328,17 @@ static int proc_readnet(struct inode * inode, struct file * file,
length = ipx_get_info(page,&start,file->f_pos,thistime);
break;
#endif /* CONFIG_IPX */
+#ifdef CONFIG_ATALK
+ case PROC_NET_ATALK:
+ length = atalk_get_info(page, &start, file->f_pos, thistime);
+ break;
+ case PROC_NET_AT_ROUTE:
+ length = atalk_rt_get_info(page, &start, file->f_pos, thistime);
+ break;
+ case PROC_NET_ATIF:
+ length = atalk_if_get_info(page, &start, file->f_pos, thistime);
+ break;
+#endif /* CONFIG_ATALK */
#ifdef CONFIG_AX25
case PROC_NET_AX25_ROUTE:
length = ax25_rt_get_info(page,&start,file->f_pos,thistime);
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 97cf2ff25..26b14816c 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -14,7 +14,7 @@
#include <linux/stat.h>
#include <linux/config.h>
-static int proc_readroot(struct inode *, struct file *, struct dirent *, int);
+static int proc_readroot(struct inode *, struct file *, void *, filldir_t);
static int proc_lookuproot(struct inode *,const char *,int,struct inode **);
static struct file_operations proc_root_operations = {
@@ -59,6 +59,10 @@ static struct proc_dir_entry root_dir[] = {
{ PROC_MEMINFO, 7, "meminfo" },
{ PROC_KMSG, 4, "kmsg" },
{ PROC_VERSION, 7, "version" },
+#ifdef CONFIG_PCI
+ { PROC_PCI, 3, "pci" },
+#endif
+ { PROC_CPUINFO, 7, "cpuinfo" },
{ PROC_SELF, 4, "self" }, /* will change inode # */
{ PROC_NET, 3, "net" },
#ifdef CONFIG_DEBUG_MALLOC
@@ -72,6 +76,10 @@ static struct proc_dir_entry root_dir[] = {
{ PROC_FILESYSTEMS, 11,"filesystems" },
{ PROC_KSYMS, 5, "ksyms" },
{ PROC_DMA, 3, "dma" },
+ { PROC_IOPORTS, 7, "ioports"},
+#ifdef CONFIG_PROFILE
+ { PROC_PROFILE, 7, "profile"},
+#endif
};
#define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
@@ -133,52 +141,44 @@ static int proc_lookuproot(struct inode * dir,const char * name, int len,
return 0;
}
+#define NUMBUF 10
+
static int proc_readroot(struct inode * inode, struct file * filp,
- struct dirent * dirent, int count)
+ void * dirent, filldir_t filldir)
{
- struct task_struct * p;
+ char buf[NUMBUF];
unsigned int nr,pid;
- int i,j;
+ unsigned long i,j;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
-repeat:
+
nr = filp->f_pos;
- if (nr < NR_ROOT_DIRENTRY) {
+ while (nr < NR_ROOT_DIRENTRY) {
struct proc_dir_entry * de = root_dir + nr;
+ if (filldir(dirent, de->name, de->namelen, nr, de->low_ino) < 0)
+ return 0;
filp->f_pos++;
- i = de->namelen;
- put_fs_long(de->low_ino, &dirent->d_ino);
- put_fs_word(i,&dirent->d_reclen);
- put_fs_byte(0,i+dirent->d_name);
- j = i;
- while (i--)
- put_fs_byte(de->name[i], i+dirent->d_name);
- return j;
- }
- nr -= NR_ROOT_DIRENTRY;
- if (nr >= NR_TASKS)
- return 0;
- filp->f_pos++;
- p = task[nr];
- if (!p || !(pid = p->pid))
- goto repeat;
- if (pid & 0xffff0000)
- goto repeat;
- j = 10;
- i = 1;
- while (pid >= j) {
- j *= 10;
- i++;
+ nr++;
}
- j = i;
- put_fs_long((pid << 16)+2, &dirent->d_ino);
- put_fs_word(i, &dirent->d_reclen);
- put_fs_byte(0, i+dirent->d_name);
- while (i--) {
- put_fs_byte('0'+(pid % 10), i+dirent->d_name);
- pid /= 10;
+
+ for (nr -= NR_ROOT_DIRENTRY; nr < NR_TASKS; nr++, filp->f_pos++) {
+ struct task_struct * p = task[nr];
+
+ if (!p || !(pid = p->pid))
+ continue;
+
+ j = NUMBUF;
+ i = pid;
+ do {
+ j--;
+ buf[j] = '0' + (i % 10);
+ i /= 10;
+ } while (i);
+
+ if (filldir(dirent, buf+j, NUMBUF-j, nr+NR_ROOT_DIRENTRY, (pid << 16)+2) < 0)
+ break;
}
- return j;
+ return 0;
}
diff --git a/fs/read_write.c b/fs/read_write.c
index 5f457b9cb..1cd19d57a 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -9,40 +9,10 @@
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/mm.h>
#include <asm/segment.h>
-/*
- * Count is now a supported feature, but currently only the ext2fs
- * uses it. A count value of 1 is supported for compatibility with
- * earlier libraries, but larger values are supported: count should
- * indicate the total buffer space available for filling with dirents.
- * The d_off entry in the dirents will then indicate the offset from
- * each dirent to the next, and the return value will indicate the
- * number of bytes written. All dirents will be written at
- * word-aligned addresses. [sct Oct 1994]
- */
-asmlinkage int sys_readdir(unsigned int fd, struct dirent * dirent, unsigned int count)
-{
- int error;
- struct file * file;
- struct inode * inode;
-
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]) ||
- !(inode = file->f_inode))
- return -EBADF;
- error = -ENOTDIR;
- if (file->f_op && file->f_op->readdir) {
- int size = count;
- if (count == 1)
- size = sizeof(*dirent);
- error = verify_area(VERIFY_WRITE, dirent, size);
- if (!error)
- error = file->f_op->readdir(inode,file,dirent,count);
- }
- return error;
-}
-
asmlinkage int sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
{
struct file * file;
diff --git a/fs/readdir.c b/fs/readdir.c
new file mode 100644
index 000000000..9a4160ac6
--- /dev/null
+++ b/fs/readdir.c
@@ -0,0 +1,145 @@
+/*
+ * linux/fs/readdir.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/stat.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/segment.h>
+
+/*
+ * Traditional linux readdir() handling..
+ *
+ * "count=1" is a special case, meaning that the buffer is one
+ * dirent-structure in size and that the code can't handle more
+ * anyway. Thus the special "fillonedir()" function for that
+ * case (the low-level handlers don't need to care about this).
+ */
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
+
+struct old_linux_dirent {
+ unsigned long d_ino;
+ unsigned long d_offset;
+ unsigned short d_namlen;
+ char d_name[1];
+};
+
+struct readdir_callback {
+ struct old_linux_dirent * dirent;
+ int count;
+};
+
+static int fillonedir(void * __buf, char * name, int namlen, off_t offset, ino_t ino)
+{
+ struct readdir_callback * buf = (struct readdir_callback *) __buf;
+ struct old_linux_dirent * dirent;
+
+ if (buf->count)
+ return -EINVAL;
+ buf->count++;
+ dirent = buf->dirent;
+ put_fs_long(ino, &dirent->d_ino);
+ put_fs_long(offset, &dirent->d_offset);
+ put_fs_word(namlen, &dirent->d_namlen);
+ memcpy_tofs(dirent->d_name, name, namlen);
+ put_fs_byte(0, dirent->d_name + namlen);
+ return 0;
+}
+
+asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count)
+{
+ int error;
+ struct file * file;
+ struct readdir_callback buf;
+
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ return -EBADF;
+ if (!file->f_op || !file->f_op->readdir)
+ return -ENOTDIR;
+ error = verify_area(VERIFY_WRITE, dirent, sizeof(struct old_linux_dirent));
+ if (error)
+ return error;
+ buf.count = 0;
+ buf.dirent = dirent;
+ error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir);
+ if (error < 0)
+ return error;
+ return buf.count;
+}
+
+/*
+ * New, all-improved, singing, dancing, iBCS2-compliant getdents()
+ * interface.
+ */
+struct linux_dirent {
+ unsigned long d_ino;
+ unsigned long d_off;
+ unsigned short d_reclen;
+ char d_name[1];
+};
+
+struct getdents_callback {
+ struct linux_dirent * current;
+ struct linux_dirent * previous;
+ int count;
+ int error;
+};
+
+static int filldir(void * __buf, char * name, int namlen, off_t offset, ino_t ino)
+{
+ struct linux_dirent * dirent;
+ struct getdents_callback * buf = (struct getdents_callback *) __buf;
+ int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
+ dirent = buf->previous;
+ if (dirent)
+ put_user(offset, &dirent->d_off);
+ dirent = buf->current;
+ buf->previous = dirent;
+ put_fs_long(ino, &dirent->d_ino);
+ put_fs_word(reclen, &dirent->d_reclen);
+ memcpy_tofs(dirent->d_name, name, namlen);
+ put_fs_byte(0, dirent->d_name + namlen);
+ ((char *) dirent) += reclen;
+ buf->current = dirent;
+ buf->count -= reclen;
+ return 0;
+}
+
+asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count)
+{
+ struct file * file;
+ struct linux_dirent * lastdirent;
+ struct getdents_callback buf;
+ int error;
+
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ return -EBADF;
+ if (!file->f_op || !file->f_op->readdir)
+ return -ENOTDIR;
+ error = verify_area(VERIFY_WRITE, dirent, count);
+ if (error)
+ return error;
+ buf.current = (struct linux_dirent *) dirent;
+ buf.previous = NULL;
+ buf.count = count;
+ buf.error = 0;
+ error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
+ if (error < 0)
+ return error;
+ lastdirent = buf.previous;
+ if (!lastdirent)
+ return buf.error;
+ put_user(file->f_pos, &lastdirent->d_off);
+ return count - buf.count;
+}
diff --git a/fs/select.c b/fs/select.c
index e87ae07eb..0b277f9d6 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -20,6 +20,7 @@
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/personality.h>
+#include <linux/mm.h>
#include <asm/segment.h>
#include <asm/system.h>
@@ -76,7 +77,7 @@ static int check(int flag, select_table * wait, struct file * file)
if ((fops = file->f_op) && (select = fops->select))
return select(inode, file, flag, wait)
|| (wait && select(inode, file, flag, NULL));
- if (S_ISREG(inode->i_mode))
+ if (flag != SEL_EX)
return 1;
return 0;
}
@@ -164,10 +165,10 @@ static int __get_fd_set(int nr, unsigned long * fs_pointer, unsigned long * fdse
if (error)
return error;
while (nr > 0) {
- *fdset = get_fs_long(fs_pointer);
+ *fdset = get_user(fs_pointer);
fdset++;
fs_pointer++;
- nr -= 32;
+ nr -= 8 * sizeof(unsigned long);
}
return 0;
}
@@ -177,10 +178,10 @@ static void __set_fd_set(int nr, unsigned long * fs_pointer, unsigned long * fds
if (!fs_pointer)
return;
while (nr > 0) {
- put_fs_long(*fdset, fs_pointer);
+ put_user(*fdset, fs_pointer);
fdset++;
fs_pointer++;
- nr -= 32;
+ nr -= 8 * sizeof(unsigned long);
}
}
@@ -198,29 +199,18 @@ __set_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp))
* Update: ERESTARTSYS breaks at least the xview clock binary, so
* I'm trying ERESTARTNOHAND which restart only when you want to.
*/
-asmlinkage int sys_select( unsigned long *buffer )
+asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
{
-/* Perform the select(nd, in, out, ex, tv) system call. */
int i;
- fd_set res_in, in, *inp;
- fd_set res_out, out, *outp;
- fd_set res_ex, ex, *exp;
- int n;
- struct timeval *tvp;
+ fd_set res_in, in;
+ fd_set res_out, out;
+ fd_set res_ex, ex;
unsigned long timeout;
- i = verify_area(VERIFY_READ, buffer, 20);
- if (i)
- return i;
- n = get_fs_long(buffer++);
if (n < 0)
return -EINVAL;
if (n > NR_OPEN)
n = NR_OPEN;
- inp = (fd_set *) get_fs_long(buffer++);
- outp = (fd_set *) get_fs_long(buffer++);
- exp = (fd_set *) get_fs_long(buffer++);
- tvp = (struct timeval *) get_fs_long(buffer);
if ((i = get_fd_set(n, inp, &in)) ||
(i = get_fd_set(n, outp, &out)) ||
(i = get_fd_set(n, exp, &ex))) return i;
@@ -236,11 +226,10 @@ asmlinkage int sys_select( unsigned long *buffer )
}
current->timeout = timeout;
i = do_select(n, &in, &out, &ex, &res_in, &res_out, &res_ex);
- if (current->timeout > jiffies)
- timeout = current->timeout - jiffies;
- else
- timeout = 0;
+ timeout = current->timeout - jiffies - 1;
current->timeout = 0;
+ if ((long) timeout < 0)
+ timeout = 0;
if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec);
timeout %= HZ;
@@ -256,3 +245,28 @@ asmlinkage int sys_select( unsigned long *buffer )
set_fd_set(n, exp, &res_ex);
return i;
}
+
+/*
+ * Perform the select(nd, in, out, ex, tv) system call.
+ * Linux/i386 didn't use to be able to handle 5 system call
+ * parameters, so the old select used a memory block for
+ * parameter passing..
+ */
+asmlinkage int old_select(unsigned long *buffer)
+{
+ int n;
+ fd_set *inp;
+ fd_set *outp;
+ fd_set *exp;
+ struct timeval *tvp;
+
+ n = verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long));
+ if (n)
+ return n;
+ n = get_user(buffer);
+ inp = (fd_set *) get_user(buffer+1);
+ outp = (fd_set *) get_user(buffer+2);
+ exp = (fd_set *) get_user(buffer+3);
+ tvp = (struct timeval *) get_user(buffer+4);
+ return sys_select(n, inp, outp, exp, tvp);
+}
diff --git a/fs/stat.c b/fs/stat.c
index 70f5d166e..dfd44c169 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -10,6 +10,8 @@
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/mm.h>
+
#include <asm/segment.h>
static void cp_old_stat(struct inode * inode, struct old_stat * statbuf)
diff --git a/fs/super.c b/fs/super.c
index 9ead32a3e..a428a7922 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -17,6 +17,7 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/locks.h>
+#include <linux/mm.h>
#include <asm/system.h>
#include <asm/segment.h>
@@ -286,6 +287,7 @@ static struct super_block * read_super(dev_t dev,char *name,int flags,
s->s_covered = NULL;
s->s_rd_only = 0;
s->s_dirt = 0;
+ s->s_type = type;
return s;
}
@@ -388,7 +390,7 @@ asmlinkage int sys_umount(char * name)
return -EACCES;
}
} else {
- if (!inode || !inode->i_sb || inode != inode->i_sb->s_mounted) {
+ if (!inode->i_sb || inode != inode->i_sb->s_mounted) {
iput(inode);
return -EINVAL;
}
@@ -516,15 +518,9 @@ static int copy_mount_options (const void * data, unsigned long *where)
if (!data)
return 0;
- for (vma = current->mm->mmap ; ; ) {
- if (!vma ||
- (unsigned long) data < vma->vm_start) {
- return -EFAULT;
- }
- if ((unsigned long) data < vma->vm_end)
- break;
- vma = vma->vm_next;
- }
+ vma = find_vma(current, (unsigned long) data);
+ if (!vma || (unsigned long) data < vma->vm_start)
+ return -EFAULT;
i = vma->vm_end - (unsigned long) data;
if (PAGE_SIZE <= (unsigned long) i)
i = PAGE_SIZE-1;
@@ -583,6 +579,7 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
if (!fstype)
return -ENODEV;
t = fstype->name;
+ fops = NULL;
if (fstype->requires_dev) {
retval = namei(dev_name,&inode);
if (retval)
@@ -600,23 +597,28 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
iput(inode);
return -ENXIO;
}
+ fops = get_blkfops(MAJOR(dev));
+ if (!fops) {
+ iput(inode);
+ return -ENOTBLK;
+ }
+ if (fops->open) {
+ struct file dummy; /* allows read-write or read-only flag */
+ memset(&dummy, 0, sizeof(dummy));
+ dummy.f_inode = inode;
+ dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;
+ retval = fops->open(inode, &dummy);
+ if (retval) {
+ iput(inode);
+ return retval;
+ }
+ }
+
} else {
if (!(dev = get_unnamed_dev()))
return -EMFILE;
inode = NULL;
}
- fops = get_blkfops(MAJOR(dev));
- if (fops && fops->open) {
- struct file dummy; /* allows read-write or read-only flag */
- memset(&dummy, 0, sizeof(dummy));
- dummy.f_inode = inode;
- dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;
- retval = fops->open(inode, &dummy);
- if (retval) {
- iput(inode);
- return retval;
- }
- }
page = 0;
if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) {
flags = new_flags & ~MS_MGC_MSK;
diff --git a/fs/sysv/Makefile b/fs/sysv/Makefile
index d4a6ecbd4..4ef1cddcd 100644
--- a/fs/sysv/Makefile
+++ b/fs/sysv/Makefile
@@ -20,6 +20,9 @@ OBJS= ialloc.o balloc.o inode.o file.o dir.o symlink.o namei.o \
sysv.o: $(OBJS)
$(LD) -r -o sysv.o $(OBJS)
+modules: sysv.o
+ ln -sf ../fs/sysv/sysv.o $(TOPDIR)/modules
+
dep:
$(CPP) -M *.c > .depend
diff --git a/fs/sysv/balloc.c b/fs/sysv/balloc.c
index f0fb850be..eddbb0bea 100644
--- a/fs/sysv/balloc.c
+++ b/fs/sysv/balloc.c
@@ -19,6 +19,10 @@
* This file contains code for allocating/freeing blocks.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/sysv_fs.h>
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index a4b019228..cfd85993e 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -13,6 +13,10 @@
* SystemV/Coherent directory handling functions
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/errno.h>
@@ -20,15 +24,12 @@
#include <linux/sysv_fs.h>
#include <linux/stat.h>
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+3) & ~3)
-
static int sysv_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
{
return -EISDIR;
}
-static int sysv_readdir(struct inode *, struct file *, struct dirent *, int);
+static int sysv_readdir(struct inode *, struct file *, void *, filldir_t);
static struct file_operations sysv_dir_operations = {
NULL, /* lseek - default */
@@ -64,15 +65,14 @@ struct inode_operations sysv_dir_inode_operations = {
NULL /* permission */
};
-static int sysv_readdir1 (struct inode * inode, struct file * filp,
- struct dirent * dirent)
+static int sysv_readdir(struct inode * inode, struct file * filp,
+ void * dirent, filldir_t filldir)
{
struct super_block * sb;
unsigned int offset,i;
- char c;
struct buffer_head * bh;
char* bh_data;
- struct sysv_dir_entry * de;
+ struct sysv_dir_entry * de, sde;
if (!inode || !(sb = inode->i_sb) || !S_ISDIR(inode->i_mode))
return -EBADF;
@@ -88,57 +88,26 @@ static int sysv_readdir1 (struct inode * inode, struct file * filp,
bh_data = bh->b_data;
while (offset < sb->sv_block_size && filp->f_pos < inode->i_size) {
de = (struct sysv_dir_entry *) (offset + bh_data);
- offset += SYSV_DIRSIZE;
- filp->f_pos += SYSV_DIRSIZE;
if (de->inode) {
- struct sysv_dir_entry sde;
-
/* Copy the directory entry first, because the directory
- * might be modified while we sleep in put_fs_byte...
+ * might be modified while we sleep in filldir()...
*/
memcpy(&sde, de, sizeof(struct sysv_dir_entry));
- for (i = 0; i < SYSV_NAMELEN; i++)
- if ((c = sde.name[i]) != 0)
- put_fs_byte(c,i+dirent->d_name);
- else
- break;
- if (i) {
- if (sde.inode > inode->i_sb->sv_ninodes)
- printk("sysv_readdir: Bad inode number on dev 0x%04x, ino %ld, offset 0x%04lx: %d is out of range\n",
- inode->i_dev, inode->i_ino, (off_t) filp->f_pos - SYSV_DIRSIZE, sde.inode);
- put_fs_long(sde.inode,&dirent->d_ino);
- put_fs_byte(0,i+dirent->d_name);
- put_fs_word(i,&dirent->d_reclen);
+ if (sde.inode > inode->i_sb->sv_ninodes)
+ printk("sysv_readdir: Bad inode number on dev 0x%04x, ino %ld, offset 0x%04lx: %d is out of range\n",
+ inode->i_dev, inode->i_ino, (off_t) filp->f_pos, sde.inode);
+
+ i = strnlen(sde.name, SYSV_NAMELEN);
+ if (filldir(dirent, sde.name, i, filp->f_pos, sde.inode) < 0) {
brelse(bh);
- return ROUND_UP(NAME_OFFSET(dirent)+i+1);
+ return 0;
}
}
+ offset += SYSV_DIRSIZE;
+ filp->f_pos += SYSV_DIRSIZE;
}
brelse(bh);
}
return 0;
}
-
-static int sysv_readdir(struct inode * inode, struct file * filp,
- struct dirent * dirent, int count)
-{
- int retval, stored;
-
- /* compatibility */
- if (count==1)
- return sysv_readdir1(inode,filp,dirent);
-
- stored = 0;
- while (count >= sizeof(struct dirent)) {
- retval = sysv_readdir1(inode,filp,dirent);
- if (retval < 0)
- return retval;
- if (!retval)
- return stored;
- dirent = (struct dirent *)((char *) dirent + retval);
- stored += retval;
- count -= retval;
- }
- return stored;
-}
diff --git a/fs/sysv/file.c b/fs/sysv/file.c
index 27f82d51a..f098af6b6 100644
--- a/fs/sysv/file.c
+++ b/fs/sysv/file.c
@@ -13,6 +13,10 @@
* SystemV/Coherent regular file handling primitives
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/kernel.h>
@@ -189,8 +193,10 @@ int sysv_file_read(struct inode * inode, struct file * filp, char * buf, int cou
if (!read)
return -EIO;
filp->f_reada = 1;
- if (!IS_RDONLY(inode))
+ if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
return read;
}
diff --git a/fs/sysv/fsync.c b/fs/sysv/fsync.c
index 9e105077d..af1218fca 100644
--- a/fs/sysv/fsync.c
+++ b/fs/sysv/fsync.c
@@ -14,6 +14,10 @@
* SystemV/Coherent fsync primitive
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/errno.h>
#include <linux/stat.h>
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index f87009100..98883c22c 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -19,6 +19,10 @@
* This file contains code for allocating/freeing inodes.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/fs.h>
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 0b61ae7c7..4aa0932cb 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -20,6 +20,14 @@
* the superblock.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -220,6 +228,7 @@ static struct super_block * detected_sysv4 (struct super_block *sb, struct buffe
sb->sv_sb_flc_blocks = &sbd->s_free[0];
sb->sv_sb_total_free_blocks = &sbd->s_tfree;
sb->sv_sb_time = &sbd->s_time;
+ sb->sv_sb_state = &sbd->s_state;
sb->sv_block_base = 0;
sb->sv_firstinodezone = 2;
sb->sv_firstdatazone = sbd->s_isize;
@@ -277,6 +286,7 @@ static struct super_block * detected_sysv2 (struct super_block *sb, struct buffe
sb->sv_sb_flc_blocks = &sbd->s_free[0];
sb->sv_sb_total_free_blocks = &sbd->s_tfree;
sb->sv_sb_time = &sbd->s_time;
+ sb->sv_sb_state = &sbd->s_state;
sb->sv_block_base = 0;
sb->sv_firstinodezone = 2;
sb->sv_firstdatazone = sbd->s_isize;
@@ -348,6 +358,7 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
panic("Coherent FS: bad super-block size");
if (64 != sizeof (struct sysv_inode))
panic("sysv fs: bad i-node size");
+ MOD_INC_USE_COUNT;
lock_super(sb);
set_blocksize(dev,BLOCK_SIZE);
@@ -390,6 +401,8 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
unlock_super(sb);
if (!silent)
printk("VFS: unable to read Xenix/SystemV/Coherent superblock on device %d/%d\n",MAJOR(dev),MINOR(dev));
+ failed:
+ MOD_DEC_USE_COUNT;
return NULL;
ok:
@@ -413,7 +426,7 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
sb->s_dev = 0;
unlock_super(sb);
printk("SysV FS: cannot read superblock in 1024 byte mode\n");
- return NULL;
+ goto failed;
}
} else {
/* Switch to another block size. Unfortunately, we have to
@@ -459,7 +472,7 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
sb->s_dev = 0;
unlock_super(sb);
printk("SysV FS: cannot read superblock in 512 byte mode\n");
- return NULL;
+ goto failed;
}
}
sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone) << sb->sv_inodes_per_block_bits;
@@ -475,8 +488,8 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
sb->s_mounted = iget(sb,SYSV_ROOT_INO);
unlock_super(sb);
if (!sb->s_mounted) {
- sysv_put_super(sb);
printk("SysV FS: get root inode failed\n");
+ sysv_put_super(sb);
return NULL;
}
sb->s_dirt = 1;
@@ -491,8 +504,15 @@ void sysv_write_super (struct super_block *sb)
lock_super(sb);
if (sb->sv_bh1->b_dirt || sb->sv_bh2->b_dirt) {
/* If we are going to write out the super block,
- then attach current time stamp. */
+ then attach current time stamp.
+ But if the filesystem was marked clean, keep it clean. */
unsigned long time = CURRENT_TIME;
+ unsigned long old_time = *sb->sv_sb_time;
+ if (sb->sv_convert)
+ old_time = from_coh_ulong(old_time);
+ if (sb->sv_type == FSTYPE_SYSV4)
+ if (*sb->sv_sb_state == 0x7c269d38 - old_time)
+ *sb->sv_sb_state = 0x7c269d38 - time;
if (sb->sv_convert)
time = to_coh_ulong(time);
*sb->sv_sb_time = time;
@@ -513,22 +533,22 @@ void sysv_put_super(struct super_block *sb)
set_blocksize(sb->s_dev,BLOCK_SIZE);
sb->s_dev = 0;
unlock_super(sb);
+ MOD_DEC_USE_COUNT;
}
-void sysv_statfs(struct super_block *sb, struct statfs *buf)
+void sysv_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
- long tmp;
-
- put_fs_long(sb->s_magic, &buf->f_type); /* type of filesystem */
- put_fs_long(sb->sv_block_size, &buf->f_bsize); /* block size */
- put_fs_long(sb->sv_ndatazones, &buf->f_blocks); /* total data blocks in file system */
- tmp = sysv_count_free_blocks(sb);
- put_fs_long(tmp, &buf->f_bfree); /* free blocks in fs */
- put_fs_long(tmp, &buf->f_bavail); /* free blocks available to non-superuser */
- put_fs_long(sb->sv_ninodes, &buf->f_files); /* total file nodes in file system */
- put_fs_long(sysv_count_free_inodes(sb), &buf->f_ffree); /* free file nodes in fs */
- put_fs_long(SYSV_NAMELEN, &buf->f_namelen);
- /* Don't know what value to put in buf->f_fsid */ /* file system id */
+ struct statfs tmp;
+
+ tmp.f_type = sb->s_magic;
+ tmp.f_bsize = sb->sv_block_size;
+ tmp.f_blocks = sb->sv_ndatazones;
+ tmp.f_bfree = sysv_count_free_blocks(sb);
+ tmp.f_bavail = tmp.f_bfree;
+ tmp.f_files = sb->sv_ninodes;
+ tmp.f_ffree = sysv_count_free_inodes(sb);
+ tmp.f_namelen = SYSV_NAMELEN;
+ memcpy_tofs(buf, &tmp, bufsiz);
}
@@ -949,3 +969,34 @@ int sysv_sync_inode(struct inode * inode)
return err;
}
+#ifdef MODULE
+
+/* Every kernel module contains stuff like this. */
+
+char kernel_version[] = UTS_RELEASE;
+
+static struct file_system_type sysv_fs_type[3] = {
+ {sysv_read_super, "xenix", 1, NULL},
+ {sysv_read_super, "sysv", 1, NULL},
+ {sysv_read_super, "coherent", 1, NULL}
+};
+
+int init_module(void)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ register_filesystem(&sysv_fs_type[i]);
+
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ unregister_filesystem(&sysv_fs_type[i]);
+}
+
+#endif
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index c9fd77158..8d245d38e 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -11,6 +11,10 @@
* Copyright (C) 1993 Bruno Haible
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -184,6 +188,7 @@ static int sysv_add_entry(struct inode * dir,
}
} else {
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->i_dirt = 1;
for (i = 0; i < SYSV_NAMELEN ; i++)
de->name[i] = (i < namelen) ? name[i] : 0;
mark_buffer_dirty(bh, 1);
diff --git a/fs/sysv/symlink.c b/fs/sysv/symlink.c
index d392816bc..c4e7d5bf5 100644
--- a/fs/sysv/symlink.c
+++ b/fs/sysv/symlink.c
@@ -13,6 +13,10 @@
* SystemV/Coherent symlink handling code
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/errno.h>
diff --git a/fs/sysv/truncate.c b/fs/sysv/truncate.c
index 21451e6dd..6de370ebd 100644
--- a/fs/sysv/truncate.c
+++ b/fs/sysv/truncate.c
@@ -11,6 +11,10 @@
* Copyright (C) 1993 Bruno Haible
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/sysv_fs.h>
diff --git a/fs/umsdos/Makefile b/fs/umsdos/Makefile
index cfba11e63..8bdf98f97 100644
--- a/fs/umsdos/Makefile
+++ b/fs/umsdos/Makefile
@@ -7,10 +7,6 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
-ifndef CONFIG_UMSDOS_FS
-CFLAGS := $(CFLAGS) -DMODULE
-endif
-
.c.s:
$(CC) $(CFLAGS) -S $<
.c.o:
@@ -24,6 +20,9 @@ OBJS= dir.o emd.o file.o inode.o ioctl.o mangle.o namei.o\
umsdos.o: $(OBJS)
$(LD) -r -o umsdos.o $(OBJS)
+modules: umsdos.o
+ ln -sf ../fs/umsdos/umsdos.o $(TOPDIR)/modules
+
clean:
rm -f core *.o *.a *.s
diff --git a/fs/umsdos/README b/fs/umsdos/README
index 4ce8b4148..320dac6ca 100644
--- a/fs/umsdos/README
+++ b/fs/umsdos/README
@@ -16,7 +16,7 @@ It gives you:
There is plenty of documentation on it in the source. A formated document
made from those comments is available from
-sunsite.unc.edu:/pub/Linux/ALPHA/umsdos
+sunsite.unc.edu:/pub/Linux/system/Filesystems/umsdos.
Mostly...
@@ -53,9 +53,9 @@ Now, how to get those --linux-.---.
$5 per directory. Add any applicable taxes.
\end joke_section
-A utility umssync creates those and maintain them. It is available
-from the same directory above (sunsite) in the file umsdos_progs-0.3.tar.gz.
-A compiled version is available in umsdos-0.3a.bin.tar.gz.
+A utility umssync creates those. The kernel maintain them. It is available
+from the same directory above (sunsite) in the file umsdos_progs-0.7.tar.gz.
+A compiled version is available in umsdos_progs-0.7.bin.tar.gz.
So in our example, after mounting mnt, we do
@@ -80,5 +80,17 @@ Umsdos won't notice new files, but will signal removed file (it won't crash).
Using umssync in /etc/rc will make sure the DOS directory is in sync with
the --linux-.---.
+It is a good idea to put the following command in your RC file just
+after the "mount -a":
+
+ mount -a
+ /sbin/umssync -i+ -c+ -r99 /umsdos_mount_point
+
+ (You put one for each umsdos mount point in the fstab)
+
+This will insure nice operation. A umsdos.fsck is in the making,
+so you will be allowed to managed umsdos partition in the same way
+other filesystem are, using the generic fsck front end.
+
Hope this helps!
diff --git a/fs/umsdos/check.c b/fs/umsdos/check.c
index d1102b4ce..7fb060c7a 100644
--- a/fs/umsdos/check.c
+++ b/fs/umsdos/check.c
@@ -1,3 +1,7 @@
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/system.h>
#include <linux/signal.h>
@@ -12,44 +16,35 @@
extern unsigned long high_memory;
-static int check_one_table(unsigned long * page_dir)
+static int check_one_table(struct pde * page_dir)
{
- unsigned long pg_table = *page_dir;
-
- if (!pg_table)
+ if (pgd_none(*page_dir))
return 0;
- if (pg_table >= high_memory || !(pg_table & PAGE_PRESENT)) {
+ if (pgd_bad(*page_dir))
return 1;
- }
return 0;
}
/*
- * This function frees up all page tables of a process when it exits.
+ * This function checks all page tables of "current"
*/
void check_page_tables(void)
{
- unsigned long pg_dir;
+ struct pgd * pg_dir;
static int err = 0;
int stack_level = (long)(&pg_dir)-current->kernel_stack_page;
if (stack_level < 1500) printk ("** %d ** ",stack_level);
- pg_dir = current->tss.cr3;
- if (mem_map[MAP_NR(pg_dir)] > 1) {
- return;
- }
- if (err == 0){
- unsigned long *page_dir = (unsigned long *) pg_dir;
- unsigned long *base = page_dir;
+ pg_dir = PAGE_DIR_OFFSET(current, 0);
+ if (err == 0) {
int i;
for (i = 0 ; i < PTRS_PER_PAGE ; i++,page_dir++){
int notok = check_one_table(page_dir);
if (notok){
err++;
- printk ("|%d| ",page_dir-base);
+ printk ("|%d:%08lx| ",i, page_dir->pgd);
}
}
- if (err) printk ("Erreur MM %d\n",err);
+ if (err) printk ("\nErreur MM %d\n",err);
}
}
-
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index 2a668d102..990260a92 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -7,6 +7,10 @@
* Extended MS-DOS directory handling functions
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/sched.h>
@@ -32,10 +36,14 @@ int UMSDOS_dir_read(struct inode *inode,struct file *filp,char *buf,
{
return -EISDIR;
}
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+3) & ~3)
+
/*
Read count directory entries from directory filp
Return a negative value from linux/errno.h.
- Return > 0 if success (the length of the file name).
+ Return > 0 if success (The amount of byte written in
+ dirent round_up to a word size (32 bits).
This function is used by the normal readdir VFS entry point and by
some function who try to find out info on a file from a pure MSDOS
@@ -72,7 +80,7 @@ static int umsdos_readdir_x(
put_fs_byte(0,dirent->d_name+3);
put_fs_word (3,&dirent->d_reclen);
if (u_entry != NULL) u_entry->flags = 0;
- ret = 3;
+ ret = ROUND_UP(NAME_OFFSET(dirent) + 3 + 1);
filp->f_pos++;
}else if (filp->f_pos < 2
|| (dir != dir->i_sb->s_mounted && filp->f_pos == 32)){
@@ -191,7 +199,7 @@ static int umsdos_readdir_x(
dirent->d_reclen = entry.name_len;
if (u_entry != NULL) *u_entry = entry;
}
- ret = entry.name_len;
+ ret = ROUND_UP(NAME_OFFSET(dirent) + entry.name_len + 1);
iput (inode);
break;
}
@@ -219,7 +227,7 @@ static int umsdos_readdir_x(
/*
Read count directory entries from directory filp
Return a negative value from linux/errno.h.
- Return > 0 if success (the length of the file name).
+ Return > 0 if success (the amount of byte written to dirent)
*/
static int UMSDOS_readdir(
struct inode *dir, /* Point to a description of the super block */
@@ -644,7 +652,7 @@ int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
if (*pt == '/') *pt++ = '\0';
if (dir->u.umsdos_i.i_emd_dir == 0){
/* This is a DOS directory */
- ret = msdos_lookup(dir,start,len,result);
+ ret = umsdos_rlookup_x(dir,start,len,result,1);
}else{
ret = umsdos_lookup_x(dir,start,len,result,1);
}
diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c
index e4d6a9470..b1ec47bf6 100644
--- a/fs/umsdos/emd.c
+++ b/fs/umsdos/emd.c
@@ -5,6 +5,10 @@
*
* Extended MS-DOS directory handling functions
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/kernel.h>
diff --git a/fs/umsdos/file.c b/fs/umsdos/file.c
index d292ea3c2..61eacaac6 100644
--- a/fs/umsdos/file.c
+++ b/fs/umsdos/file.c
@@ -7,6 +7,10 @@
* Extended MS-DOS regular file handling primitives
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <asm/system.h>
@@ -33,8 +37,10 @@ static int UMSDOS_file_read(
{
/* We have to set the access time because msdos don't care */
int ret = msdos_file_read(inode,filp,buf,count);
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
+ if (!IS_RDONLY(inode)){
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
return ret;
}
/*
@@ -58,16 +64,8 @@ static void UMSDOS_truncate(struct inode *inode)
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
inode->i_dirt = 1;
}
-/*
- See inode.c
-
- Some entry point are filled dynamically with function pointers
- from the msdos file_operations and file_inode_operations.
-
- The idea is to have the code as independent as possible from
- the msdos file system.
-*/
+/* Function for normal file system (512 bytes hardware sector size) */
struct file_operations umsdos_file_operations = {
NULL, /* lseek - default */
UMSDOS_file_read, /* read */
@@ -94,10 +92,41 @@ struct inode_operations umsdos_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ msdos_bmap, /* bmap */
UMSDOS_truncate,/* truncate */
NULL, /* permission */
msdos_smap /* smap */
};
+/* For other with larger and unaligned file system */
+struct file_operations umsdos_file_operations_no_bmap = {
+ NULL, /* lseek - default */
+ UMSDOS_file_read, /* read */
+ UMSDOS_file_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ msdos_mmap, /* mmap */
+ NULL, /* no special open is needed */
+ NULL, /* release */
+ file_fsync /* fsync */
+};
+struct inode_operations umsdos_file_inode_operations_no_bmap = {
+ &umsdos_file_operations_no_bmap, /* default file operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ UMSDOS_truncate,/* truncate */
+ NULL, /* permission */
+ NULL, /* smap */
+};
diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c
index 40f7feb68..22be740cc 100644
--- a/fs/umsdos/inode.c
+++ b/fs/umsdos/inode.c
@@ -6,6 +6,14 @@
*
*/
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
#include <linux/fs.h>
#include <linux/msdos_fs.h>
#include <linux/kernel.h>
@@ -13,15 +21,9 @@
#include <linux/errno.h>
#include <asm/segment.h>
#include <linux/string.h>
-#include <linux/ctype.h>
#include <linux/stat.h>
#include <linux/umsdos_fs.h>
-#ifdef MODULE
- #include <linux/module.h>
- #include "../../tools/version.h"
-#endif
-
struct inode *pseudo_root=NULL; /* Useful to simulate the pseudo DOS */
/* directory. See UMSDOS_readdir_x() */
@@ -45,6 +47,9 @@ void UMSDOS_put_inode(struct inode *inode)
PRINTK (("put inode %x owner %x pos %d dir %x\n",inode
,inode->u.umsdos_i.i_emd_owner,inode->u.umsdos_i.pos
,inode->u.umsdos_i.i_emd_dir));
+ if (inode != NULL && inode == pseudo_root){
+ printk ("Umsdos: Oops releasing pseudo_root. Notify jacques@solucorp.qc.ca\n");
+ }
msdos_put_inode(inode);
}
@@ -52,15 +57,13 @@ void UMSDOS_put_inode(struct inode *inode)
void UMSDOS_put_super(struct super_block *sb)
{
msdos_put_super(sb);
- #ifdef MODULE
- MOD_DEC_USE_COUNT;
- #endif
+ MOD_DEC_USE_COUNT;
}
-void UMSDOS_statfs(struct super_block *sb,struct statfs *buf)
+void UMSDOS_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
{
- msdos_statfs(sb,buf);
+ msdos_statfs(sb,buf,bufsiz);
}
@@ -152,18 +155,11 @@ void umsdos_patch_inode (
if (!umsdos_isinit(inode)){
inode->u.umsdos_i.i_emd_dir = 0;
if (S_ISREG(inode->i_mode)){
- static char is_init = 0;
- if (!is_init){
- /*
- I don't want to change the msdos file system code
- so I get the address of some subroutine dynamically
- once.
- */
- umsdos_file_inode_operations.bmap = inode->i_op->bmap;
+ if (inode->i_op->bmap != NULL){
inode->i_op = &umsdos_file_inode_operations;
- is_init = 1;
+ }else{
+ inode->i_op = &umsdos_file_inode_operations_no_bmap;
}
- inode->i_op = &umsdos_file_inode_operations;
}else if (S_ISDIR(inode->i_mode)){
if (dir != NULL){
umsdos_setup_dir_inode(inode);
@@ -408,8 +404,10 @@ struct super_block *UMSDOS_read_super(
which do not have an EMD file. They behave like normal
msdos directory, with all limitation of msdos.
*/
- struct super_block *sb = msdos_read_super(s,data,silent);
- printk ("UMSDOS Alpha 0.5a (compatibility level %d.%d, fast msdos)\n"
+ struct super_block *sb;
+ MOD_INC_USE_COUNT;
+ sb = msdos_read_super(s,data,silent);
+ printk ("UMSDOS Beta 0.6 (compatibility level %d.%d, fast msdos)\n"
,UMSDOS_VERSION,UMSDOS_RELEASE);
if (sb != NULL){
sb->s_op = &umsdos_sops;
@@ -420,8 +418,8 @@ struct super_block *UMSDOS_read_super(
/* #Specification: pseudo root / mount
When a umsdos fs is mounted, a special handling is done
if it is the root partition. We check for the presence
- of the file /linux/etc/init or /linux/etc/rc.
- If one is there, we do a chroot("/linux").
+ of the file /linux/etc/init or /linux/etc/rc or
+ /linux/sbin/init. If one is there, we do a chroot("/linux").
We check both because (see init/main.c) the kernel
try to exec init at different place and if it fails
@@ -454,32 +452,48 @@ struct super_block *UMSDOS_read_super(
,UMSDOS_PSDROOT_LEN,&pseudo)==0
&& S_ISDIR(pseudo->i_mode)){
struct inode *etc = NULL;
- struct inode *rc = NULL;
+ struct inode *sbin = NULL;
+ int pseudo_ok = 0;
Printk (("/%s is there\n",UMSDOS_PSDROOT_NAME));
if (umsdos_real_lookup (pseudo,"etc",3,&etc)==0
&& S_ISDIR(etc->i_mode)){
- struct inode *init;
+ struct inode *init = NULL;
+ struct inode *rc = NULL;
Printk (("/%s/etc is there\n",UMSDOS_PSDROOT_NAME));
if ((umsdos_real_lookup (etc,"init",4,&init)==0
&& S_ISREG(init->i_mode))
|| (umsdos_real_lookup (etc,"rc",2,&rc)==0
&& S_ISREG(rc->i_mode))){
- umsdos_setup_dir_inode (pseudo);
- Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME));
- pseudo_root = pseudo;
- pseudo->i_count++;
- pseudo = NULL;
+ pseudo_ok = 1;
}
iput (init);
iput (rc);
}
+ if (!pseudo_ok
+ && umsdos_real_lookup (pseudo,"sbin",4,&sbin)==0
+ && S_ISDIR(sbin->i_mode)){
+ struct inode *init = NULL;
+ Printk (("/%s/sbin is there\n",UMSDOS_PSDROOT_NAME));
+ if (umsdos_real_lookup (sbin,"init",4,&init)==0
+ && S_ISREG(init->i_mode)){
+ pseudo_ok = 1;
+ }
+ iput (init);
+ }
+ if (pseudo_ok){
+ umsdos_setup_dir_inode (pseudo);
+ Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME));
+ pseudo_root = pseudo;
+ pseudo->i_count++;
+ pseudo = NULL;
+ }
+ iput (sbin);
iput (etc);
}
iput (pseudo);
}
- #ifdef MODULE
- MOD_INC_USE_COUNT;
- #endif
+ } else {
+ MOD_DEC_USE_COUNT;
}
return sb;
}
@@ -501,12 +515,7 @@ int init_module(void)
void cleanup_module(void)
{
- if (MOD_IN_USE)
- printk("Umsdos: file system in use, remove delayed\n");
- else
- {
- unregister_filesystem(&umsdos_fs_type);
- }
+ unregister_filesystem(&umsdos_fs_type);
}
#endif
diff --git a/fs/umsdos/ioctl.c b/fs/umsdos/ioctl.c
index 972571796..d766ef939 100644
--- a/fs/umsdos/ioctl.c
+++ b/fs/umsdos/ioctl.c
@@ -5,6 +5,10 @@
*
* Extended MS-DOS ioctl directory handling functions
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -160,6 +164,21 @@ int UMSDOS_ioctl_dir (
umsdos_parse (data.umsdos_dirent.name
,data.umsdos_dirent.name_len,&info);
ret = umsdos_newentry (dir,&info);
+ }else if (cmd == UMSDOS_RENAME_DOS){
+ /* #Specification: ioctl / UMSDOS_RENAME_DOS
+ A file or directory is rename in a DOS directory
+ (not moved across directory). The source name
+ is in the dos_dirent.name field and the destination
+ is in umsdos_dirent.name field.
+
+ This ioctl allows umssync to rename a mangle file
+ name before syncing it back in the EMD.
+ */
+ dir->i_count += 2;
+ ret = msdos_rename (dir
+ ,data.dos_dirent.d_name,data.dos_dirent.d_reclen
+ ,dir
+ ,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
}else if (cmd == UMSDOS_UNLINK_EMD){
/* #Specification: ioctl / UMSDOS_UNLINK_EMD
The umsdos_dirent field of the struct umsdos_ioctl is used
diff --git a/fs/umsdos/mangle.c b/fs/umsdos/mangle.c
index 1f59447e9..a7649a39a 100644
--- a/fs/umsdos/mangle.c
+++ b/fs/umsdos/mangle.c
@@ -6,6 +6,10 @@
* Control the mangling of file name to fit msdos name space.
* Many optimisation by GLU == dglaude@is1.vub.ac.be (GLAUDE DAVID)
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/errno.h>
#include <linux/ctype.h>
#include <linux/string.h>
@@ -222,13 +226,15 @@ int umsdos_parse (
with a special character as the first character
of the extension will be mangled. This solve the
following problem:
-
+
+ #
touch FILE
# FILE is invalid for DOS, so mangling is applied
# file.{_1 is created in the DOS directory
touch file.{_1
# To UMSDOS file point to a single DOS entry.
# So file.{_1 has to be mangled.
+ #
*/
static char special[]={
SPECIAL_MANGLING,'\0'
@@ -270,7 +276,9 @@ int umsdos_parse (
Control character are converted to #.
Space are converted to #.
The following character are also converted to #.
+ #
" * + , / : ; < = > ? [ \ ] | ~
+ #
Sometime, the problem is not in MsDOS itself but in
command.com.
@@ -294,7 +302,7 @@ int umsdos_parse (
*/
}else{
/* Conforming MSDOS file name */
- strcpy (info->fake.fname,fname); /* GLU C'est sur on a un 0 a la fin */
+ strncpy (info->fake.fname,fname,len);
info->msdos_reject = 0;
base_len = firstpt != NULL ? (int)(firstpt - fname) : len;
}
@@ -316,10 +324,12 @@ int umsdos_parse (
Here is the list of DOS pseudo devices:
+ #
"prn","con","aux","nul",
"lpt1","lpt2","lpt3","lpt4",
"com1","com2","com3","com4",
"clock$"
+ #
and some standard ones for common DOS programs
diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c
index 567039e14..42820bb98 100644
--- a/fs/umsdos/namei.c
+++ b/fs/umsdos/namei.c
@@ -6,6 +6,10 @@
*
* Maintain and access the --linux alternate directory file.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -315,7 +319,7 @@ static int umsdos_rename_f(
int flags) /* 0 == copy flags from old_name */
/* != 0, this is the value of flags */
{
- int ret = EPERM;
+ int ret = -EPERM;
struct umsdos_info old_info;
int old_ret = umsdos_parse (old_name,old_len,&old_info);
struct umsdos_info new_info;
@@ -330,58 +334,79 @@ chkstk();
chkstk();
PRINTK (("ret %d ",ret));
if (ret == 0){
- PRINTK (("new newentry "));
- umsdos_ren_init(&new_info,&old_info,flags);
- ret = umsdos_newentry (new_dir,&new_info);
-chkstk();
- PRINTK (("ret %d %d ",ret,new_info.fake.len));
- if (ret == 0){
- PRINTK (("msdos_rename "));
- old_dir->i_count++;
- new_dir->i_count++; /* Both inode are needed later */
- ret = msdos_rename (old_dir
- ,old_info.fake.fname,old_info.fake.len
- ,new_dir
- ,new_info.fake.fname,new_info.fake.len);
-chkstk();
- PRINTK (("after m_rename ret %d ",ret));
- if (ret != 0){
- umsdos_delentry (new_dir,&new_info
- ,S_ISDIR(new_info.entry.mode));
-chkstk();
- }else{
- ret = umsdos_delentry (old_dir,&old_info
- ,S_ISDIR(old_info.entry.mode));
+ /* check sticky bit on old_dir */
+ if ( !(old_dir->i_mode & S_ISVTX) || fsuser() ||
+ current->fsuid == old_info.entry.uid ||
+ current->fsuid == old_dir->i_uid ) {
+ /* Does new_name already exist? */
+ PRINTK(("new findentry "));
+ ret = umsdos_findentry(new_dir,&new_info,0);
+ if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */
+ !(new_dir->i_mode & S_ISVTX) || fsuser() ||
+ current->fsuid == new_info.entry.uid ||
+ current->fsuid == new_dir->i_uid ) {
+ PRINTK (("new newentry "));
+ umsdos_ren_init(&new_info,&old_info,flags);
+ ret = umsdos_newentry (new_dir,&new_info);
chkstk();
+ PRINTK (("ret %d %d ",ret,new_info.fake.len));
if (ret == 0){
- /*
- This UMSDOS_lookup does not look very useful.
- It makes sure that the inode of the file will
- be correctly setup (umsdos_patch_inode()) in
- case it is already in use.
-
- Not very efficient ...
- */
- struct inode *inode;
- new_dir->i_count++;
- PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
- ret = UMSDOS_lookup (new_dir,new_name,new_len
- ,&inode);
+ PRINTK (("msdos_rename "));
+ old_dir->i_count++;
+ new_dir->i_count++; /* Both inode are needed later */
+ ret = msdos_rename (old_dir
+ ,old_info.fake.fname,old_info.fake.len
+ ,new_dir
+ ,new_info.fake.fname,new_info.fake.len);
chkstk();
+ PRINTK (("after m_rename ret %d ",ret));
if (ret != 0){
- printk ("UMSDOS: partial rename for file %s\n"
- ,new_info.entry.name);
+ umsdos_delentry (new_dir,&new_info
+ ,S_ISDIR(new_info.entry.mode));
+chkstk();
}else{
- /*
- Update f_pos so notify_change will succeed
- if the file was already in use.
- */
- umsdos_set_dirinfo (inode,new_dir,new_info.f_pos);
+ ret = umsdos_delentry (old_dir,&old_info
+ ,S_ISDIR(old_info.entry.mode));
chkstk();
- iput (inode);
+ if (ret == 0){
+ /*
+ This UMSDOS_lookup does not look very useful.
+ It makes sure that the inode of the file will
+ be correctly setup (umsdos_patch_inode()) in
+ case it is already in use.
+
+ Not very efficient ...
+ */
+ struct inode *inode;
+ new_dir->i_count++;
+ PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
+ ret = UMSDOS_lookup (new_dir,new_name,new_len
+ ,&inode);
+chkstk();
+ if (ret != 0){
+ printk ("UMSDOS: partial rename for file %s\n"
+ ,new_info.entry.name);
+ }else{
+ /*
+ Update f_pos so notify_change will succeed
+ if the file was already in use.
+ */
+ umsdos_set_dirinfo (inode,new_dir,new_info.f_pos);
+chkstk();
+ iput (inode);
+ }
+ }
}
}
+ }else{
+ /* sticky bit set on new_dir */
+ PRINTK(("sticky set on new "));
+ ret = -EPERM;
}
+ }else{
+ /* sticky bit set on old_dir */
+ PRINTK(("sticky set on old "));
+ ret = -EPERM;
}
}
umsdos_unlockcreate(old_dir);
@@ -483,6 +508,7 @@ int UMSDOS_link (
Given a file /foo/file
+ #
ln /foo/file /tmp/file2
become internally
@@ -490,6 +516,7 @@ int UMSDOS_link (
mv /foo/file /foo/-LINK1
ln -s /foo/-LINK1 /foo/file
ln -s /foo/-LINK1 /tmp/file2
+ #
Using this strategy, we can operate on /foo/file or /foo/file2.
We can remove one and keep the other, like a normal Unix hard link.
@@ -502,6 +529,7 @@ int UMSDOS_link (
The strategy for hard link introduces a side effect that
may or may not be acceptable. Here is the sequence
+ #
mkdir subdir1
touch subdir1/file
mkdir subdir2
@@ -509,6 +537,7 @@ int UMSDOS_link (
rm subdir1/file
rmdir subdir1
rmdir: subdir1: Directory not empty
+ #
This happen because there is an invisible file (--link) in
subdir1 which is referenced by subdir2/file.
@@ -519,12 +548,14 @@ int UMSDOS_link (
Another weakness of hard link come from the fact that
it is based on hidden symbolic links. Here is an example.
+ #
mkdir /subdir1
touch /subdir1/file
mkdir /subdir2
ln /subdir1/file subdir2/file
mv /subdir1 subdir3
ls -l /subdir2/file
+ #
Since /subdir2/file is a hidden symbolic link
to /subdir1/..hlinkNNN, accessing it will fail since
@@ -765,6 +796,7 @@ int UMSDOS_rmdir(
but you rapidly get iput() all around. Here is an exemple
of what I am trying to avoid.
+ #
if (a){
...
if(b){
@@ -783,10 +815,12 @@ int UMSDOS_rmdir(
}
// Was iput finally done ?
return status;
+ #
Here is the style I am using. Still sometime I do the
first when things are very simple (or very complicated :-( )
+ #
if (a){
if (b){
...
@@ -797,6 +831,7 @@ int UMSDOS_rmdir(
...
}
return status;
+ #
Again, while this help clarifying the code, I often get a lot
of iput(), unlike the first style, where I can place few
@@ -812,6 +847,7 @@ int UMSDOS_rmdir(
where an iput() is done, the inode is simply nulled, disabling
the last one.
+ #
if (a){
if (b){
...
@@ -824,6 +860,7 @@ int UMSDOS_rmdir(
}
iput (dir);
return status;
+ #
Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
pair goes against this practice of "forgetting" the inode as soon
@@ -842,28 +879,37 @@ int UMSDOS_rmdir(
ret = -EBUSY;
}else if ((empty = umsdos_isempty (sdir)) != 0){
PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
- if (empty == 1){
- /* We have to removed the EMD file */
- ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
- ,UMSDOS_EMD_NAMELEN);
+ /* check sticky bit */
+ if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
+ current->fsuid == sdir->i_uid ||
+ current->fsuid == dir->i_uid ) {
+ if (empty == 1){
+ /* We have to removed the EMD file */
+ ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
+ ,UMSDOS_EMD_NAMELEN);
+ sdir = NULL;
+ }
+ /* sdir must be free before msdos_rmdir() */
+ iput (sdir);
sdir = NULL;
- }
- /* sdir must be free before msdos_rmdir() */
- iput (sdir);
- sdir = NULL;
- PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
- if (ret == 0){
- struct umsdos_info info;
- dir->i_count++;
- umsdos_parse (name,len,&info);
- /* The findentry is there only to complete */
- /* the mangling */
- umsdos_findentry (dir,&info,2);
- ret = msdos_rmdir (dir,info.fake.fname
- ,info.fake.len);
+ PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
if (ret == 0){
- ret = umsdos_delentry (dir,&info,1);
+ struct umsdos_info info;
+ dir->i_count++;
+ umsdos_parse (name,len,&info);
+ /* The findentry is there only to complete */
+ /* the mangling */
+ umsdos_findentry (dir,&info,2);
+ ret = msdos_rmdir (dir,info.fake.fname
+ ,info.fake.len);
+ if (ret == 0){
+ ret = umsdos_delentry (dir,&info,1);
+ }
}
+ }else{
+ /* sticky bit set and we don't have permission */
+ PRINTK(("sticky set "));
+ ret = -EPERM;
}
}else{
/*
@@ -887,63 +933,72 @@ int UMSDOS_unlink (
const char * name,
int len)
{
- struct umsdos_info info;
int ret = umsdos_nevercreat(dir,name,len,-EPERM);
if (ret == 0){
+ struct umsdos_info info;
ret = umsdos_parse (name,len,&info);
if (ret == 0){
umsdos_lockcreate(dir);
ret = umsdos_findentry(dir,&info,1);
if (ret == 0){
PRINTK (("UMSDOS_unlink %s ",info.fake.fname));
- if (info.entry.flags & UMSDOS_HLINK){
- /* #Specification: hard link / deleting a link
- When we deletes a file, and this file is a link
- we must subtract 1 to the nlink field of the
- hidden link.
-
- If the count goes to 0, we delete this hidden
- link too.
- */
- /*
- First, get the inode of the hidden link
- using the standard lookup function.
- */
- struct inode *inode;
- dir->i_count++;
- ret = UMSDOS_lookup (dir,name,len,&inode);
- if (ret == 0){
- PRINTK (("unlink nlink = %d ",inode->i_nlink));
- inode->i_nlink--;
- if (inode->i_nlink == 0){
- struct inode *hdir = iget(inode->i_sb
- ,inode->u.umsdos_i.i_dir_owner);
- struct umsdos_dirent entry;
- ret = umsdos_inode2entry (hdir,inode,&entry);
- if (ret == 0){
- ret = UMSDOS_unlink (hdir,entry.name
- ,entry.name_len);
+ /* check sticky bit */
+ if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
+ current->fsuid == info.entry.uid ||
+ current->fsuid == dir->i_uid ) {
+ if (info.entry.flags & UMSDOS_HLINK){
+ /* #Specification: hard link / deleting a link
+ When we deletes a file, and this file is a link
+ we must subtract 1 to the nlink field of the
+ hidden link.
+
+ If the count goes to 0, we delete this hidden
+ link too.
+ */
+ /*
+ First, get the inode of the hidden link
+ using the standard lookup function.
+ */
+ struct inode *inode;
+ dir->i_count++;
+ ret = UMSDOS_lookup (dir,name,len,&inode);
+ if (ret == 0){
+ PRINTK (("unlink nlink = %d ",inode->i_nlink));
+ inode->i_nlink--;
+ if (inode->i_nlink == 0){
+ struct inode *hdir = iget(inode->i_sb
+ ,inode->u.umsdos_i.i_dir_owner);
+ struct umsdos_dirent entry;
+ ret = umsdos_inode2entry (hdir,inode,&entry);
+ if (ret == 0){
+ ret = UMSDOS_unlink (hdir,entry.name
+ ,entry.name_len);
+ }else{
+ iput (hdir);
+ }
}else{
- iput (hdir);
+ struct iattr newattrs;
+ newattrs.ia_valid = 0;
+ ret = UMSDOS_notify_change (inode, &newattrs);
}
- }else{
- struct iattr newattrs;
- newattrs.ia_valid = 0;
- ret = UMSDOS_notify_change (inode, &newattrs);
+ iput (inode);
}
- iput (inode);
}
- }
- if (ret == 0){
- ret = umsdos_delentry (dir,&info,0);
if (ret == 0){
- PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
- dir->i_count++;
- ret = msdos_unlink_umsdos (dir,info.fake.fname
- ,info.fake.len);
- PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname
- ,info.entry.mode,ret));
+ ret = umsdos_delentry (dir,&info,0);
+ if (ret == 0){
+ PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
+ dir->i_count++;
+ ret = msdos_unlink_umsdos (dir,info.fake.fname
+ ,info.fake.len);
+ PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname
+ ,info.entry.mode,ret));
+ }
}
+ }else{
+ /* sticky bit set and we've not got permission */
+ PRINTK(("sticky set "));
+ ret = -EPERM;
}
}
umsdos_unlockcreate(dir);
@@ -986,7 +1041,7 @@ int UMSDOS_rename(
,new_len,0);
if (ret == -EEXIST){
/* #Specification: rename / new name exist
- If the destination name already exist, it will
+ If the destination name already exist, it will
silently be removed. EXT2 does it this way
and this is the spec of SUNOS. So does UMSDOS.
diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c
index d7272ed96..d708709bd 100644
--- a/fs/umsdos/rdir.c
+++ b/fs/umsdos/rdir.c
@@ -7,6 +7,10 @@
* (For directory without EMD file).
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/sched.h>
@@ -32,8 +36,10 @@ static int UMSDOS_rreaddir (
{
int ret = 0;
while (1){
+ int len = -1;
ret = msdos_readdir(dir,filp,dirent,count);
- if (ret == 5
+ if (ret > 0) len = get_fs_word(&dirent->d_reclen);
+ if (len == 5
&& pseudo_root != NULL
&& dir->i_sb->s_mounted == pseudo_root->i_sb->s_mounted){
/*
@@ -45,7 +51,7 @@ static int UMSDOS_rreaddir (
if (memcmp(name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN)!=0) break;
}else{
if (pseudo_root != NULL
- && ret == 2
+ && len == 2
&& dir == dir->i_sb->s_mounted
&& dir == pseudo_root->i_sb->s_mounted){
char name[2];
@@ -60,11 +66,18 @@ static int UMSDOS_rreaddir (
return ret;
}
-int UMSDOS_rlookup(
+/*
+ Lookup into a non promoted directory.
+ If the result is a directory, make sure we find out if it is
+ a promoted one or not (calling umsdos_setup_dir_inode(inode)).
+*/
+int umsdos_rlookup_x(
struct inode *dir,
const char *name,
int len,
- struct inode **result) /* Will hold inode of the file, if successful */
+ struct inode **result, /* Will hold inode of the file, if successful */
+ int nopseudo) /* Don't care about pseudo root mode */
+ /* so locating "linux" will work */
{
int ret;
if (pseudo_root != NULL
@@ -84,7 +97,7 @@ int UMSDOS_rlookup(
ret = umsdos_real_lookup (dir,name,len,result);
if (ret == 0){
struct inode *inode = *result;
- if (inode == pseudo_root){
+ if (inode == pseudo_root && !nopseudo){
/* #Specification: pseudo root / DOS/linux
Even in the real root directory (c:\), the directory
/linux won't show
@@ -102,6 +115,14 @@ int UMSDOS_rlookup(
iput (dir);
return ret;
}
+int UMSDOS_rlookup(
+ struct inode *dir,
+ const char *name,
+ int len,
+ struct inode **result) /* Will hold inode of the file, if successful */
+{
+ return umsdos_rlookup_x(dir,name,len,result,0);
+}
static int UMSDOS_rrmdir (
struct inode *dir,
diff --git a/fs/umsdos/symlink.c b/fs/umsdos/symlink.c
index 1b1e561c2..6ab27c5dd 100644
--- a/fs/umsdos/symlink.c
+++ b/fs/umsdos/symlink.c
@@ -6,6 +6,9 @@
*
* Extended MS-DOS regular file handling primitives
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
#include <asm/segment.h>
#include <asm/system.h>
diff --git a/fs/xiafs/Makefile b/fs/xiafs/Makefile
index 097563244..b8a19d0bf 100644
--- a/fs/xiafs/Makefile
+++ b/fs/xiafs/Makefile
@@ -20,6 +20,9 @@ OBJS= bitmap.o truncate.o namei.o inode.o \
xiafs.o: $(OBJS)
$(LD) -r -o xiafs.o $(OBJS)
+modules: xiafs.o
+ ln -sf ../fs/xiafs/xiafs.o $(TOPDIR)/modules
+
dep:
$(CPP) -M *.c > .depend
diff --git a/fs/xiafs/bitmap.c b/fs/xiafs/bitmap.c
index ca93d1546..bca7e4367 100644
--- a/fs/xiafs/bitmap.c
+++ b/fs/xiafs/bitmap.c
@@ -11,6 +11,10 @@
/* bitmap.c contains the code that handles the inode and block bitmaps */
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/sched.h>
#include <linux/locks.h>
#include <linux/xia_fs.h>
@@ -54,7 +58,7 @@ zone_found:
for (j=0; j < 32; j++)
if (tmp & (1 << j))
break;
- if (set_bit(j, bmap+i)) {
+ if (set_bit(j,bmap+i)) {
start_bit=j + (i << 5) + 1;
goto repeat;
}
diff --git a/fs/xiafs/dir.c b/fs/xiafs/dir.c
index d9db56ddc..5a88c2f0b 100644
--- a/fs/xiafs/dir.c
+++ b/fs/xiafs/dir.c
@@ -9,6 +9,10 @@
* This software may be redistributed per Linux Copyright.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/sched.h>
#include <linux/errno.h>
@@ -19,11 +23,8 @@
#include "xiafs_mac.h"
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+3) & ~3)
-
static int xiafs_dir_read(struct inode *, struct file *, char *, int);
-static int xiafs_readdir(struct inode *, struct file *, struct dirent *, int);
+static int xiafs_readdir(struct inode *, struct file *, void *, filldir_t);
static struct file_operations xiafs_dir_operations = {
NULL, /* lseek - default */
@@ -65,10 +66,10 @@ static int xiafs_dir_read(struct inode * inode,
return -EISDIR;
}
-static int xiafs_readdir(struct inode * inode,
- struct file * filp, struct dirent * dirent, int count)
+static int xiafs_readdir(struct inode * inode, struct file * filp,
+ void * dirent, filldir_t filldir)
{
- u_int offset, i,ret;
+ u_int offset, i;
struct buffer_head * bh;
struct xiafs_direct * de;
@@ -76,8 +77,7 @@ static int xiafs_readdir(struct inode * inode,
return -EBADF;
if (inode->i_size & (XIAFS_ZSIZE(inode->i_sb) - 1) )
return -EBADF;
- ret = 0;
- while (!ret && filp->f_pos < inode->i_size) {
+ while (filp->f_pos < inode->i_size) {
offset = filp->f_pos & (XIAFS_ZSIZE(inode->i_sb) - 1);
bh = xiafs_bread(inode, filp->f_pos >> XIAFS_ZSIZE_BITS(inode->i_sb),0);
if (!bh) {
@@ -93,7 +93,7 @@ static int xiafs_readdir(struct inode * inode,
offset = i;
de = (struct xiafs_direct *) (offset + bh->b_data);
- while (!ret && offset < XIAFS_ZSIZE(inode->i_sb) && filp->f_pos < inode->i_size) {
+ while (offset < XIAFS_ZSIZE(inode->i_sb) && filp->f_pos < inode->i_size) {
if (de->d_ino > inode->i_sb->u.xiafs_sb.s_ninodes ||
de->d_rec_len < 12 ||
(char *)de+de->d_rec_len > XIAFS_ZSIZE(inode->i_sb)+bh->b_data ||
@@ -104,21 +104,18 @@ static int xiafs_readdir(struct inode * inode,
brelse(bh);
return 0;
}
- offset += de->d_rec_len;
- filp->f_pos += de->d_rec_len;
if (de->d_ino) {
- for (i = 0; i < de->d_name_len ; i++)
- put_fs_byte(de->d_name[i],i+dirent->d_name);
- put_fs_byte(0,i+dirent->d_name);
- put_fs_long(de->d_ino,&dirent->d_ino);
- put_fs_word(i,&dirent->d_reclen);
if (!IS_RDONLY (inode)) {
- inode->i_atime=CURRENT_TIME;
+ inode->i_atime=CURRENT_TIME;
inode->i_dirt=1;
}
- ret = ROUND_UP(NAME_OFFSET(dirent)+i+1);
- break;
+ if (filldir(dirent, de->d_name, de->d_name_len, filp->f_pos, de->d_ino) < 0) {
+ brelse(bh);
+ return 0;
+ }
}
+ offset += de->d_rec_len;
+ filp->f_pos += de->d_rec_len;
de = (struct xiafs_direct *) (offset + bh->b_data);
}
brelse(bh);
@@ -131,5 +128,5 @@ static int xiafs_readdir(struct inode * inode,
inode->i_atime=CURRENT_TIME;
inode->i_dirt=1;
}
- return ret;
+ return 0;
}
diff --git a/fs/xiafs/file.c b/fs/xiafs/file.c
index 5678ffd0b..c67daaed9 100644
--- a/fs/xiafs/file.c
+++ b/fs/xiafs/file.c
@@ -9,6 +9,10 @@
* This software may be redistributed per Linux Copyright.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <asm/system.h>
diff --git a/fs/xiafs/fsync.c b/fs/xiafs/fsync.c
index 67681b2c6..5bd0a7066 100644
--- a/fs/xiafs/fsync.c
+++ b/fs/xiafs/fsync.c
@@ -8,6 +8,10 @@
* xiafs fsync primitive
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <asm/system.h>
diff --git a/fs/xiafs/inode.c b/fs/xiafs/inode.c
index 171499a95..5f9fc833a 100644
--- a/fs/xiafs/inode.c
+++ b/fs/xiafs/inode.c
@@ -9,6 +9,14 @@
* This software may be redistributed per Linux Copyright.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
#include <linux/sched.h>
#include <linux/xia_fs.h>
#include <linux/kernel.h>
@@ -43,6 +51,7 @@ void xiafs_put_super(struct super_block *sb)
for(i = 0 ; i < _XIAFS_ZMAP_SLOTS ; i++)
brelse(sb->u.xiafs_sb.s_zmap_buf[i]);
unlock_super(sb);
+ MOD_DEC_USE_COUNT;
}
static struct super_operations xiafs_sops = {
@@ -63,6 +72,7 @@ struct super_block *xiafs_read_super(struct super_block *s, void *data,
struct xiafs_super_block *sp;
int i, z, dev;
+ MOD_INC_USE_COUNT;
dev=s->s_dev;
lock_super(s);
@@ -72,6 +82,7 @@ struct super_block *xiafs_read_super(struct super_block *s, void *data,
s->s_dev=0;
unlock_super(s);
printk("XIA-FS: read super_block failed (%s %d)\n", WHERE_ERR);
+ MOD_DEC_USE_COUNT;
return NULL;
}
sp = (struct xiafs_super_block *) bh->b_data;
@@ -83,6 +94,7 @@ struct super_block *xiafs_read_super(struct super_block *s, void *data,
if (!silent)
printk("VFS: Can't find a xiafs filesystem on dev 0x%04x.\n",
dev);
+ MOD_DEC_USE_COUNT;
return NULL;
}
s->s_blocksize = sp->s_zone_size;
@@ -93,7 +105,10 @@ struct super_block *xiafs_read_super(struct super_block *s, void *data,
brelse(bh);
set_blocksize(dev, s->s_blocksize);
bh = bread (dev, 0, s->s_blocksize);
- if(!bh) return NULL;
+ if(!bh) {
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
sp = (struct xiafs_super_block *) (((char *)bh->b_data) + BLOCK_SIZE) ;
};
s->u.xiafs_sb.s_nzones = sp->s_nzones;
@@ -152,23 +167,23 @@ xiafs_read_super_fail:
s->s_dev=0;
unlock_super(s);
printk("XIA-FS: read bitmaps failed (%s %d)\n", WHERE_ERR);
+ MOD_DEC_USE_COUNT;
return NULL;
}
-void xiafs_statfs(struct super_block *sb, struct statfs *buf)
+void xiafs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
- long tmp;
-
- put_fs_long(_XIAFS_SUPER_MAGIC, &buf->f_type);
- put_fs_long(XIAFS_ZSIZE(sb), &buf->f_bsize);
- put_fs_long(sb->u.xiafs_sb.s_ndatazones, &buf->f_blocks);
- tmp = xiafs_count_free_zones(sb);
- put_fs_long(tmp, &buf->f_bfree);
- put_fs_long(tmp, &buf->f_bavail);
- put_fs_long(sb->u.xiafs_sb.s_ninodes, &buf->f_files);
- put_fs_long(xiafs_count_free_inodes(sb), &buf->f_ffree);
- put_fs_long(_XIAFS_NAME_LEN, &buf->f_namelen);
- /* don't know what should be put in buf->f_fsid */
+ struct statfs tmp;
+
+ tmp.f_type = _XIAFS_SUPER_MAGIC;
+ tmp.f_bsize = XIAFS_ZSIZE(sb);
+ tmp.f_blocks = sb->u.xiafs_sb.s_ndatazones;
+ tmp.f_bfree = xiafs_count_free_zones(sb);
+ tmp.f_bavail = tmp.f_bfree;
+ tmp.f_files = sb->u.xiafs_sb.s_ninodes;
+ tmp.f_ffree = xiafs_count_free_inodes(sb);
+ tmp.f_namelen = _XIAFS_NAME_LEN;
+ memcpy_tofs(buf, &tmp, bufsiz);
}
static int zone_bmap(struct buffer_head * bh, int nr)
@@ -500,3 +515,26 @@ int xiafs_sync_inode (struct inode *inode)
brelse (bh);
return err;
}
+
+#ifdef MODULE
+
+/* Every kernel module contains stuff like this. */
+
+char kernel_version[] = UTS_RELEASE;
+
+static struct file_system_type xiafs_fs_type = {
+ xiafs_read_super, "xiafs", 1, NULL
+};
+
+int init_module(void)
+{
+ register_filesystem(&xiafs_fs_type);
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unregister_filesystem(&xiafs_fs_type);
+}
+
+#endif
diff --git a/fs/xiafs/namei.c b/fs/xiafs/namei.c
index 0532b1754..46b3590b2 100644
--- a/fs/xiafs/namei.c
+++ b/fs/xiafs/namei.c
@@ -9,6 +9,10 @@
* This software may be redistributed per Linux Copyright.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/sched.h>
#include <linux/xia_fs.h>
#include <linux/kernel.h>
@@ -356,6 +360,7 @@ int xiafs_mkdir(struct inode * dir, const char * name, int len, int mode)
inode->i_op = &xiafs_dir_inode_operations;
inode->i_size = XIAFS_ZSIZE(dir->i_sb);
inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ inode->i_dirt = 1;
dir_block = xiafs_bread(inode,0,1);
if (!dir_block) {
iput(dir);
@@ -758,8 +763,7 @@ try_again:
retval = -EEXIST;
if (new_bh)
goto end_rename;
- retval = -EACCES;
- if (!permission(old_inode, MAY_WRITE))
+ if ((retval = permission(old_inode, MAY_WRITE)) != 0)
goto end_rename;
retval = -EINVAL;
if (subdir(new_dir, old_inode))
diff --git a/fs/xiafs/symlink.c b/fs/xiafs/symlink.c
index 757ad5796..1c64ebc6d 100644
--- a/fs/xiafs/symlink.c
+++ b/fs/xiafs/symlink.c
@@ -9,6 +9,10 @@
* This software may be redistributed per Linux Copyright.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/segment.h>
#include <linux/errno.h>
diff --git a/fs/xiafs/truncate.c b/fs/xiafs/truncate.c
index bdb9d39be..2e8dec10d 100644
--- a/fs/xiafs/truncate.c
+++ b/fs/xiafs/truncate.c
@@ -9,6 +9,10 @@
* This software may be redistributed per Linux Copyright.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/xia_fs.h>