summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-05-07 02:55:41 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-05-07 02:55:41 +0000
commitdcec8a13bf565e47942a1751a9cec21bec5648fe (patch)
tree548b69625b18cc2e88c3e68d0923be546c9ebb03 /fs
parent2e0f55e79c49509b7ff70ff1a10e1e9e90a3dfd4 (diff)
o Merge with Linux 2.1.99.
o Fix ancient bug in the ELF loader making ldd crash. o Fix ancient bug in the keyboard code for SGI, SNI and Jazz.
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.in3
-rw-r--r--fs/Makefile11
-rw-r--r--fs/adfs/super.c4
-rw-r--r--fs/affs/super.c3
-rw-r--r--fs/autofs/inode.c3
-rw-r--r--fs/autofs/root.c14
-rw-r--r--fs/binfmt_aout.c5
-rw-r--r--fs/binfmt_elf.c389
-rw-r--r--fs/binfmt_misc.c10
-rw-r--r--fs/buffer.c79
-rw-r--r--fs/coda/inode.c4
-rw-r--r--fs/dcache.c99
-rw-r--r--fs/devpts/.cvsignore2
-rw-r--r--fs/devpts/Makefile10
-rw-r--r--fs/devpts/devpts_i.h42
-rw-r--r--fs/devpts/inode.c374
-rw-r--r--fs/devpts/root.c170
-rw-r--r--fs/exec.c71
-rw-r--r--fs/ext2/balloc.c202
-rw-r--r--fs/ext2/dir.c15
-rw-r--r--fs/ext2/file.c97
-rw-r--r--fs/ext2/ialloc.c151
-rw-r--r--fs/ext2/inode.c124
-rw-r--r--fs/ext2/ioctl.c11
-rw-r--r--fs/ext2/namei.c192
-rw-r--r--fs/ext2/super.c12
-rw-r--r--fs/fat/inode.c4
-rw-r--r--fs/filesystems.c5
-rw-r--r--fs/hfs/super.c6
-rw-r--r--fs/hpfs/hpfs_fs.c3
-rw-r--r--fs/isofs/inode.c4
-rw-r--r--fs/minix/inode.c4
-rw-r--r--fs/namei.c2
-rw-r--r--fs/ncpfs/inode.c5
-rw-r--r--fs/ncpfs/ncplib_kernel.c8
-rw-r--r--fs/ncpfs/ncpsign_kernel.c8
-rw-r--r--fs/nfs/inode.c7
-rw-r--r--fs/nfs/nfsroot.c113
-rw-r--r--fs/ntfs/fs.c7
-rw-r--r--fs/ntfs/types.h2
-rw-r--r--fs/proc/fd.c2
-rw-r--r--fs/proc/inode.c118
-rw-r--r--fs/proc/link.c8
-rw-r--r--fs/proc/mem.c3
-rw-r--r--fs/proc/openpromfs.c28
-rw-r--r--fs/proc/proc_devtree.c13
-rw-r--r--fs/proc/root.c22
-rw-r--r--fs/romfs/inode.c3
-rw-r--r--fs/smbfs/inode.c5
-rw-r--r--fs/super.c20
-rw-r--r--fs/sysv/inode.c11
-rw-r--r--fs/ufs/ufs_super.c4
-rw-r--r--fs/umsdos/README-WIP.txt87
-rw-r--r--fs/umsdos/dir.c44
-rw-r--r--fs/umsdos/emd.c68
-rw-r--r--fs/umsdos/file.c35
-rw-r--r--fs/umsdos/inode.c48
-rw-r--r--fs/umsdos/ioctl.c25
-rw-r--r--fs/umsdos/namei.c113
-rw-r--r--fs/umsdos/rdir.c10
60 files changed, 2082 insertions, 860 deletions
diff --git a/fs/Config.in b/fs/Config.in
index 54ce86b39..ad0c2a675 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -62,7 +62,7 @@ tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
tristate 'Amiga FFS filesystem support' CONFIG_AFFS_FS
tristate 'Apple Macintosh filesystem support (experimental)' CONFIG_HFS_FS
tristate 'ROM filesystem support' CONFIG_ROMFS_FS
-tristate 'Kernel automounter support (experimental)' CONFIG_AUTOFS_FS
+tristate 'Kernel automounter support' CONFIG_AUTOFS_FS
if [ "$CONFIG_AFFS_FS" != "n" ]; then
define_bool CONFIG_AMIGA_PARTITION y
fi
@@ -77,6 +77,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'ADFS filesystem support (read only) (EXPERIMENTAL)' CONFIG_ADFS_FS
+ tristate '/dev/pts filesystem support (EXPERIMENTAL)' CONFIG_DEVPTS_FS
fi
bool 'Macintosh partition map support' CONFIG_MAC_PARTITION
endmenu
diff --git a/fs/Makefile b/fs/Makefile
index bc97a3f33..c5973dd39 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -17,7 +17,8 @@ O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \
MOD_LIST_NAME := FS_MODULES
ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
- hpfs sysv smbfs ncpfs ufs affs romfs autofs hfs lockd nfsd nls
+ hpfs sysv smbfs ncpfs ufs affs romfs autofs hfs lockd nfsd \
+ nls devpts
ifeq ($(CONFIG_QUOTA),y)
O_OBJS += dquot.o
@@ -234,6 +235,14 @@ else
endif
endif
+ifeq ($(CONFIG_DEVPTS_FS),y)
+SUB_DIRS += devpts
+else
+ ifeq ($(CONFIG_DEVPTS_FS),m)
+ MOD_SUB_DIRS += devpts
+ endif
+endif
+
ifeq ($(CONFIG_BINFMT_ELF),y)
BINFMTS += binfmt_elf.o
else
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 3ddd5d5cc..234d8cf21 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -98,13 +98,11 @@ static struct super_operations adfs_sops = {
static void adfs_put_super (struct super_block *sb)
{
int i;
- lock_super (sb);
- sb->s_dev = 0;
+
for (i = 0; i < sb->u.adfs_sb.s_map_size; i++)
brelse (sb->u.adfs_sb.s_map[i]);
kfree (sb->u.adfs_sb.s_map);
brelse (sb->u.adfs_sb.s_sbh);
- unlock_super (sb);
MOD_DEC_USE_COUNT;
}
diff --git a/fs/affs/super.c b/fs/affs/super.c
index b4ce6756f..ed6ae67b3 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -46,7 +46,6 @@ affs_put_super(struct super_block *sb)
pr_debug("affs_put_super()\n");
- lock_super(sb);
for (i = 0; i < sb->u.affs_sb.s_bm_count; i++)
affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh);
if (!(sb->s_flags & MS_RDONLY)) {
@@ -67,8 +66,6 @@ affs_put_super(struct super_block *sb)
*/
set_blocksize(sb->s_dev, sb->u.affs_sb.s_blksize);
- sb->s_dev = 0;
- unlock_super(sb);
MOD_DEC_USE_COUNT;
return;
}
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index cbcefc34a..d17115208 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -41,16 +41,13 @@ static void autofs_put_super(struct super_block *sb)
if ( !sbi->catatonic )
autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */
- lock_super(sb);
autofs_hash_nuke(&sbi->dirhash);
for ( n = 0 ; n < AUTOFS_MAX_SYMLINKS ; n++ ) {
if ( test_bit(n, sbi->symlink_bitmap) )
kfree(sbi->symlink[n].data);
}
- sb->s_dev = 0;
kfree(sb->u.generic_sbp);
- unlock_super(sb);
DPRINTK(("autofs: shutting down\n"));
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 36d38b84e..60f9efe01 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -109,8 +109,7 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
if ( !(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) ) {
do {
if ( status && dentry->d_inode ) {
- printk("autofs: lookup failure on existing dentry, status = %d, name = %s\n", status, dentry->d_name.name);
- printk("autofs: trying to recover, but prepare for Armageddon\n");
+ printk("autofs warning: lookup failure on existing dentry, status = %d, name = %s\n", status, dentry->d_name.name);
break;
}
@@ -146,7 +145,10 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
return !autofs_wait(sbi, &dentry->d_name);
}
- autofs_update_usage(&sbi->dirhash,ent);
+ /* We don't update the usages for the autofs daemon itself, this
+ is necessary for recursive autofs mounts */
+ if ( !autofs_oz_mode(sbi) )
+ autofs_update_usage(&sbi->dirhash,ent);
dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
return 1;
@@ -188,8 +190,10 @@ static int autofs_revalidate(struct dentry * dentry)
}
/* Update the usage list */
- ent = (struct autofs_dir_ent *) dentry->d_time;
- autofs_update_usage(&sbi->dirhash,ent);
+ if ( !autofs_oz_mode(sbi) ) {
+ ent = (struct autofs_dir_ent *) dentry->d_time;
+ autofs_update_usage(&sbi->dirhash,ent);
+ }
return 1;
}
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index be58c11ed..f47f467ec 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -349,7 +349,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
return retval;
/* OK, This is the point of no return */
-#ifdef __sparc__
+#if defined(__sparc__) && !defined(__sparc_v9__)
memcpy(&current->tss.core_exec, &ex, sizeof(struct exec));
#endif
@@ -362,8 +362,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
current->mm->rss = 0;
current->mm->mmap = NULL;
- current->suid = current->euid = current->fsuid = bprm->e_uid;
- current->sgid = current->egid = current->fsgid = bprm->e_gid;
+ compute_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
#ifdef __sparc__
if (N_MAGIC(ex) == NMAGIC) {
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index e75692a3f..22cc1fd5f 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -39,17 +39,11 @@
#include <linux/elf.h>
-#undef DEBUG_ELF
-
static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
static int load_elf_library(int fd);
extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
extern void dump_thread(struct pt_regs *, struct user *);
-#ifdef __sparc__
-extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
-#endif
-
#ifndef elf_addr_t
#define elf_addr_t unsigned long
#define elf_caddr_t char *
@@ -77,27 +71,6 @@ static struct linux_binfmt elf_format = {
#endif
};
-#ifdef DEBUG_ELF
-/* Debugging routines. */
-static void print_elf_p_type(Elf32_Word p_type)
-{
- int i = (int) p_type;
-
- switch(i) {
- case PT_NULL: printk("<PT_NULL> "); break;
- case PT_LOAD: printk("<PT_LOAD> "); break;
- case PT_DYNAMIC: printk("<PT_DYNAMIC> "); break;
- case PT_INTERP: printk("<PT_INTERP> "); break;
- case PT_NOTE: printk("<PT_NOTE> "); break;
- case PT_SHLIB: printk("<PT_SHLIB> "); break;
- case PT_PHDR: printk("<PT_PHDR> "); break;
- case PT_LOPROC: printk("<PT_LOPROC/REGINFO> "); break;
- case PT_HIPROC: printk("<PT_HIPROC> "); break;
- default: printk("<whee %08lx> ", (unsigned long) i); break;
- }
-}
-#endif /* (DEBUG_ELF) */
-
static void set_brk(unsigned long start, unsigned long end)
{
start = ELF_PAGEALIGN(start);
@@ -127,10 +100,11 @@ static void padzero(unsigned long elf_bss)
}
}
-static elf_addr_t *
+static elf_addr_t *
create_elf_tables(char *p, int argc, int envc,
struct elfhdr * exec,
unsigned long load_addr,
+ unsigned long load_bias,
unsigned long interp_load_addr, int ibcs)
{
elf_caddr_t *argv;
@@ -167,10 +141,9 @@ create_elf_tables(char *p, int argc, int envc,
csp -= ((exec ? DLINFO_ITEMS*2 : 4) + (k_platform ? 2 : 0));
csp -= envc+1;
csp -= argc+1;
- csp -= (!ibcs ? 3 : 1); /* argc itself */
- if ((unsigned long)csp & 15UL) {
+ csp -= (!ibcs ? 3 : 1); /* argc itself */
+ if ((unsigned long)csp & 15UL)
sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);
- }
/*
* Put the ELF interpreter info on the stack
@@ -197,7 +170,7 @@ create_elf_tables(char *p, int argc, int envc,
NEW_AUX_ENT(3, AT_PAGESZ, ELF_EXEC_PAGESIZE);
NEW_AUX_ENT(4, AT_BASE, interp_load_addr);
NEW_AUX_ENT(5, AT_FLAGS, 0);
- NEW_AUX_ENT(6, AT_ENTRY, (elf_addr_t) exec->e_entry);
+ NEW_AUX_ENT(6, AT_ENTRY, load_bias + exec->e_entry);
NEW_AUX_ENT(7, AT_UID, (elf_addr_t) current->uid);
NEW_AUX_ENT(8, AT_EUID, (elf_addr_t) current->euid);
NEW_AUX_ENT(9, AT_GID, (elf_addr_t) current->gid);
@@ -242,136 +215,108 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
unsigned long *interp_load_addr)
{
struct file * file;
- struct elf_phdr *elf_phdata = NULL;
+ struct elf_phdr *elf_phdata;
struct elf_phdr *eppnt;
- unsigned long load_addr;
+ unsigned long load_addr = 0;
int load_addr_set = 0;
+ unsigned long last_bss = 0, elf_bss = 0;
+ unsigned long error = ~0UL;
int elf_exec_fileno;
- int retval;
- unsigned long last_bss, elf_bss;
- unsigned long error;
- int i;
-
- elf_bss = 0;
- last_bss = 0;
- error = load_addr = 0;
+ int retval, i, size;
/* First of all, some simple consistency checks */
- if ((interp_elf_ex->e_type != ET_EXEC &&
- interp_elf_ex->e_type != ET_DYN) ||
- !elf_check_arch(interp_elf_ex->e_machine) ||
- (!interpreter_dentry->d_inode->i_op ||
- !interpreter_dentry->d_inode->i_op->default_file_ops->mmap)){
-
-#ifdef DEBUG_ELF
- printk("bad e_type %d ", interp_elf_ex->e_type);
-#endif
- return ~0UL;
- }
-
- /* Now read in all of the header information */
-
- if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > ELF_EXEC_PAGESIZE) {
- return ~0UL;
- }
-
- elf_phdata = (struct elf_phdr *)
- kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
- GFP_KERNEL);
- if (!elf_phdata) {
- return ~0UL;
- }
+ if (interp_elf_ex->e_type != ET_EXEC &&
+ interp_elf_ex->e_type != ET_DYN)
+ goto out;
+ if (!elf_check_arch(interp_elf_ex->e_machine))
+ goto out;
+ if (!interpreter_dentry->d_inode->i_op ||
+ !interpreter_dentry->d_inode->i_op->default_file_ops->mmap)
+ goto out;
/*
* If the size of this structure has changed, then punt, since
* we will be doing the wrong thing.
*/
if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
- {
- kfree(elf_phdata);
- return ~0UL;
- }
+ goto out;
- retval = read_exec(interpreter_dentry, interp_elf_ex->e_phoff,
- (char *) elf_phdata,
- sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
+ /* Now read in all of the header information */
- if (retval < 0) {
- kfree (elf_phdata);
- return retval;
- }
+ size = sizeof(struct elf_phdr) * interp_elf_ex->e_phnum;
+ if (size > ELF_EXEC_PAGESIZE)
+ goto out;
+ elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
+ if (!elf_phdata)
+ goto out;
- elf_exec_fileno = open_dentry(interpreter_dentry, O_RDONLY);
- if (elf_exec_fileno < 0) {
- kfree(elf_phdata);
- return ~0UL;
- }
+ retval = read_exec(interpreter_dentry, interp_elf_ex->e_phoff,
+ (char *) elf_phdata, size, 1);
+ error = retval;
+ if (retval < 0)
+ goto out_free;
- file = current->files->fd[elf_exec_fileno];
+ error = ~0UL;
+ elf_exec_fileno = open_dentry(interpreter_dentry, O_RDONLY);
+ if (elf_exec_fileno < 0)
+ goto out_free;
+ file = fget(elf_exec_fileno);
eppnt = elf_phdata;
- for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
+ for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
if (eppnt->p_type == PT_LOAD) {
int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
int elf_prot = 0;
unsigned long vaddr = 0;
- unsigned long k;
+ unsigned long k, map_addr;
if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
- if (interp_elf_ex->e_type == ET_EXEC || load_addr_set ||
-#ifdef __mips__
- 1) /* Always load the program interpreter absolute. */
-#else
- 0)
-#endif
- {
+ vaddr = eppnt->p_vaddr;
+ if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
elf_type |= MAP_FIXED;
- vaddr = eppnt->p_vaddr;
#ifdef __sparc__
} else {
load_addr = get_unmapped_area(0, eppnt->p_filesz +
- ELF_PAGEOFFSET(eppnt->p_vaddr));
+ ELF_PAGEOFFSET(vaddr), 0);
#endif
}
-
- error = do_mmap(file,
- ELF_PAGESTART(vaddr) + load_addr,
+
+ map_addr = do_mmap(file,
+ load_addr + ELF_PAGESTART(vaddr),
eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr),
elf_prot,
elf_type,
eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
-
- if (error > -1024UL) {
- /* Real error */
- sys_close(elf_exec_fileno);
- kfree(elf_phdata);
- return ~0UL;
- }
+ if (map_addr > -1024UL) /* Real error */
+ goto out_close;
- if (!load_addr && interp_elf_ex->e_type == ET_DYN)
- load_addr = (vaddr & 0xfffff000) - error;
+ if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
+ load_addr = map_addr - + ELF_PAGESTART(vaddr);
+ load_addr_set = 1;
+ }
/*
- * Find the end of the file mapping for this phdr, and keep
+ * Find the end of the file mapping for this phdr, and keep
* track of the largest address we see for this.
*/
k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
- if (k > elf_bss) elf_bss = k;
+ if (k > elf_bss)
+ elf_bss = k;
/*
* Do the same thing for the memory mapping - between
* elf_bss and last_bss is the bss section.
*/
k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
- if (k > last_bss) last_bss = k;
+ if (k > last_bss)
+ last_bss = k;
}
+ }
/* Now use mmap to map the library into memory. */
- sys_close(elf_exec_fileno);
-
/*
* Now fill out the bss section. First pad the last page up
* to the page boundary, and then perform a mmap to make sure
@@ -391,7 +336,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
error = ((unsigned long) interp_elf_ex->e_entry) + load_addr;
out_close:
-// fput(file);
+ fput(file);
sys_close(elf_exec_fileno);
out_free:
kfree(elf_phdata);
@@ -453,180 +398,166 @@ out:
static inline int
do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
{
- struct elfhdr elf_ex;
- struct elfhdr interp_elf_ex;
struct file * file;
- struct exec interp_ex;
struct dentry *interpreter_dentry = NULL; /* to shut gcc up */
- unsigned long load_addr, load_bias;
+ unsigned long load_addr = 0, load_bias;
int load_addr_set = 0;
+ char * elf_interpreter = NULL;
unsigned int interpreter_type = INTERPRETER_NONE;
- unsigned char ibcs2_interpreter;
- int i;
+ unsigned char ibcs2_interpreter = 0;
mm_segment_t old_fs;
unsigned long error;
struct elf_phdr * elf_ppnt, *elf_phdata;
- int elf_exec_fileno;
unsigned long elf_bss, k, elf_brk;
- int retval;
- char * elf_interpreter;
+ int elf_exec_fileno;
+ int retval, size, i;
unsigned long elf_entry, interp_load_addr = 0;
- int status;
unsigned long start_code, end_code, end_data;
+ struct elfhdr elf_ex;
+ struct elfhdr interp_elf_ex;
+ struct exec interp_ex;
char passed_fileno[6];
- ibcs2_interpreter = 0;
- status = 0;
- load_addr = 0;
- elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
- return -ENOEXEC;
- }
-
+ /* Get the exec-header */
+ elf_ex = *((struct elfhdr *) bprm->buf);
+ retval = -ENOEXEC;
/* First of all, some simple consistency checks */
- if ((elf_ex.e_type != ET_EXEC &&
- elf_ex.e_type != ET_DYN) ||
- (! elf_check_arch(elf_ex.e_machine)) ||
- (!bprm->dentry->d_inode->i_op || !bprm->dentry->d_inode->i_op->default_file_ops ||
- !bprm->dentry->d_inode->i_op->default_file_ops->mmap)){
- return -ENOEXEC;
- }
+ if (elf_ex.e_ident[0] != 0x7f ||
+ strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0)
+ goto out;
+ if (elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN)
+ goto out;
+ if (!elf_check_arch(elf_ex.e_machine))
+ goto out;
#ifdef __mips__
/* IRIX binaries handled elsewhere. */
- if(elf_ex.e_flags & EF_MIPS_ARCH)
- return -ENOEXEC;
+ if (elf_ex.e_flags & EF_MIPS_ARCH) {
+ retval = -ENOEXEC;
+ goto out;
+ }
#endif
+ if (!bprm->dentry->d_inode->i_op ||
+ !bprm->dentry->d_inode->i_op->default_file_ops ||
+ !bprm->dentry->d_inode->i_op->default_file_ops->mmap)
+ goto out;
/* Now read in all of the header information */
- elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize *
- elf_ex.e_phnum, GFP_KERNEL);
- if (elf_phdata == NULL) {
- return -ENOMEM;
- }
+ retval = -ENOMEM;
+ size = elf_ex.e_phentsize * elf_ex.e_phnum;
+ elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
+ if (!elf_phdata)
+ goto out;
- retval = read_exec(bprm->dentry, elf_ex.e_phoff, (char *) elf_phdata,
- elf_ex.e_phentsize * elf_ex.e_phnum, 1);
- if (retval < 0) {
- kfree (elf_phdata);
- return retval;
- }
+ retval = read_exec(bprm->dentry, elf_ex.e_phoff,
+ (char *) elf_phdata, size, 1);
+ if (retval < 0)
+ goto out_free_ph;
- elf_ppnt = elf_phdata;
+ retval = open_dentry(bprm->dentry, O_RDONLY);
+ if (retval < 0)
+ goto out_free_ph;
+ elf_exec_fileno = retval;
+ file = fget(elf_exec_fileno);
+ elf_ppnt = elf_phdata;
elf_bss = 0;
elf_brk = 0;
- elf_exec_fileno = open_dentry(bprm->dentry, O_RDONLY);
-
- if (elf_exec_fileno < 0) {
- kfree (elf_phdata);
- return elf_exec_fileno;
- }
-
- file = current->files->fd[elf_exec_fileno];
-
- elf_interpreter = NULL;
start_code = ~0UL;
end_code = 0;
end_data = 0;
- for(i=0;i < elf_ex.e_phnum; i++){
+ for (i = 0; i < elf_ex.e_phnum; i++) {
if (elf_ppnt->p_type == PT_INTERP) {
- if ( elf_interpreter != NULL )
- {
- kfree (elf_phdata);
- kfree(elf_interpreter);
- sys_close(elf_exec_fileno);
- return -EINVAL;
- }
+ retval = -EINVAL;
+ if (elf_interpreter)
+ goto out_free_interp;
/* This is the program interpreter used for
* shared libraries - for now assume that this
* is an a.out format binary
*/
+ retval = -ENOMEM;
elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
GFP_KERNEL);
- if (elf_interpreter == NULL) {
- kfree (elf_phdata);
- sys_close(elf_exec_fileno);
- return -ENOMEM;
- }
+ if (!elf_interpreter)
+ goto out_free_file;
- retval = read_exec(bprm->dentry,elf_ppnt->p_offset,
+ retval = read_exec(bprm->dentry, elf_ppnt->p_offset,
elf_interpreter,
elf_ppnt->p_filesz, 1);
+ if (retval < 0)
+ goto out_free_interp;
/* If the program interpreter is one of these two,
- then assume an iBCS2 image. Otherwise assume
- a native linux image. */
+ * then assume an iBCS2 image. Otherwise assume
+ * a native linux image.
+ */
if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0)
- ibcs2_interpreter = 1;
+ ibcs2_interpreter = 1;
#if 0
printk("Using ELF interpreter %s\n", elf_interpreter);
#endif
- if (retval >= 0) {
- old_fs = get_fs(); /* This could probably be optimized */
- set_fs(get_ds());
+ old_fs = get_fs(); /* This could probably be optimized */
+ set_fs(get_ds());
#ifdef __sparc__
- if (ibcs2_interpreter) {
- unsigned long old_pers = current->personality;
+ if (ibcs2_interpreter) {
+ unsigned long old_pers = current->personality;
- current->personality = PER_SVR4;
- interpreter_dentry = open_namei(elf_interpreter, 0, 0);
- current->personality = old_pers;
- } else
+ current->personality = PER_SVR4;
+ interpreter_dentry = open_namei(elf_interpreter,
+ 0, 0);
+ current->personality = old_pers;
+ } else
#endif
- interpreter_dentry = open_namei(elf_interpreter, 0, 0);
- set_fs(old_fs);
- if (IS_ERR(interpreter_dentry))
- retval = PTR_ERR(interpreter_dentry);
- }
-
- if (retval >= 0)
- retval = read_exec(interpreter_dentry,0,bprm->buf,128, 1);
-
- if (retval >= 0) {
- interp_ex = *((struct exec *) bprm->buf); /* exec-header */
- interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-
- }
- if (retval < 0) {
- kfree (elf_phdata);
- kfree(elf_interpreter);
- sys_close(elf_exec_fileno);
- return retval;
- }
+ interpreter_dentry = open_namei(elf_interpreter,
+ 0, 0);
+ set_fs(old_fs);
+ retval = PTR_ERR(interpreter_dentry);
+ if (IS_ERR(interpreter_dentry))
+ goto out_free_interp;
+ retval = permission(interpreter_dentry->d_inode, MAY_EXEC);
+ if (retval < 0)
+ goto out_free_dentry;
+ retval = read_exec(interpreter_dentry, 0, bprm->buf, 128, 1);
+ if (retval < 0)
+ goto out_free_dentry;
+
+ /* Get the exec headers */
+ interp_ex = *((struct exec *) bprm->buf);
+ interp_elf_ex = *((struct elfhdr *) bprm->buf);
}
elf_ppnt++;
}
/* Some simple consistency checks for the interpreter */
- if (elf_interpreter){
+ if (elf_interpreter) {
interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
/* Now figure out which format our binary is */
if ((N_MAGIC(interp_ex) != OMAGIC) &&
(N_MAGIC(interp_ex) != ZMAGIC) &&
(N_MAGIC(interp_ex) != QMAGIC))
- interpreter_type = INTERPRETER_ELF;
+ interpreter_type = INTERPRETER_ELF;
if (interp_elf_ex.e_ident[0] != 0x7f ||
- strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
- interpreter_type &= ~INTERPRETER_ELF;
+ strncmp(&interp_elf_ex.e_ident[1], "ELF", 3) != 0)
+ interpreter_type &= ~INTERPRETER_ELF;
+ retval = -ELIBBAD;
if (!interpreter_type)
- {
- kfree(elf_interpreter);
- kfree(elf_phdata);
- sys_close(elf_exec_fileno);
- return -ELIBBAD;
- }
+ goto out_free_dentry;
+
+ /* Make sure only one type was selected */
+ if ((interpreter_type & INTERPRETER_ELF) &&
+ interpreter_type != INTERPRETER_ELF) {
+ printk(KERN_WARNING "ELF: Ambiguous type, using ELF\n");
+ interpreter_type = INTERPRETER_ELF;
+ }
}
/* OK, we are done with that, now set up the arg stuff,
@@ -658,6 +589,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
current->mm->end_data = 0;
current->mm->end_code = 0;
current->mm->mmap = NULL;
+ current->flags &= ~PF_FORKNOEXEC; /* accounting flags */
elf_entry = (unsigned long) elf_ex.e_entry;
/* Do this immediately, since STACK_TOP as used in setup_arg_pages
@@ -686,7 +618,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
if (elf_ppnt->p_type == PT_LOAD) {
int elf_prot = 0, elf_flags;
- unsigned long vaddr = 0;
+ unsigned long vaddr;
if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
@@ -694,8 +626,8 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
+ vaddr = elf_ppnt->p_vaddr;
if (elf_ex.e_type == ET_EXEC || load_addr_set) {
- vaddr = elf_ppnt->p_vaddr;
elf_flags |= MAP_FIXED;
}
@@ -712,7 +644,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
load_addr = (elf_ppnt->p_vaddr -
elf_ppnt->p_offset);
if (elf_ex.e_type == ET_DYN) {
- load_bias = error;
+ load_bias = error - ELF_PAGESTART(load_bias + vaddr);
load_addr += error;
}
}
@@ -731,7 +663,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
}
}
set_fs(old_fs);
-// fput(file); /* all done with the file */
+ fput(file); /* all done with the file */
elf_entry += load_bias;
elf_bss += load_bias;
@@ -779,15 +711,14 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
#ifndef VM_STACK_FLAGS
current->executable = dget(bprm->dentry);
#endif
- current->suid = current->euid = current->fsuid = bprm->e_uid;
- current->sgid = current->egid = current->fsgid = bprm->e_gid;
+ compute_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
bprm->p = (unsigned long)
create_elf_tables((char *)bprm->p,
bprm->argc,
bprm->envc,
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
- load_addr,
+ load_addr, load_bias,
interp_load_addr,
(interpreter_type == INTERPRETER_AOUT ? 0 : 1));
/* N.B. passed_fileno might not be initialized? */
@@ -806,7 +737,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
padzero(elf_bss);
-#ifdef DEBUG_ELF
+#if 0
printk("(start_brk) %x\n" , current->mm->start_brk);
printk("(end_code) %x\n" , current->mm->end_code);
printk("(start_code) %x\n" , current->mm->start_code);
@@ -850,7 +781,7 @@ out_free_interp:
if (elf_interpreter)
kfree(elf_interpreter);
out_free_file:
-// fput(file);
+ fput(file);
sys_close(elf_exec_fileno);
out_free_ph:
kfree(elf_phdata);
@@ -1056,7 +987,7 @@ static int notesize(struct memelfnote *en)
/* #define DEBUG */
-#if defined (DEBUG) && defined (__i386__)
+#ifdef DEBUG
static void dump_regs(const char *str, elf_greg_t *r)
{
int i;
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 8f8579d7c..bc1da662e 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -34,7 +34,7 @@
struct binfmt_entry {
struct binfmt_entry *next;
- int id;
+ long id;
int flags; /* type, status, etc. */
int offset; /* offset of magic */
int size; /* size of magic/mask */
@@ -243,7 +243,7 @@ _ret:
static char *copyarg(char **dp, const char **sp, int *count,
char del, int special, int *err)
{
- char c, *res = *dp;
+ char c = 0, *res = *dp;
while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) {
switch (c) {
@@ -370,7 +370,7 @@ static int proc_read_status(char *page, char **start, off_t off,
if (!data)
sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
else {
- if (!(e = get_entry((int) data))) {
+ if (!(e = get_entry((long) data))) {
err = -ENOENT;
goto _err;
}
@@ -428,7 +428,7 @@ static int proc_write_status(struct file *file, const char *buffer,
count--;
if ((count == 1) && !(buffer[0] & ~('0' | '1'))) {
if (data) {
- if ((e = get_entry((int) data)))
+ if ((e = get_entry((long) data)))
e->flags = (e->flags & ~ENTRY_ENABLED)
| (int)(buffer[0] - '0');
put_entry(e);
@@ -437,7 +437,7 @@ static int proc_write_status(struct file *file, const char *buffer,
}
} else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) {
if (data)
- clear_entry((int) data);
+ clear_entry((long) data);
else
clear_entries();
} else {
diff --git a/fs/buffer.c b/fs/buffer.c
index 1d58146ae..5e55f89c7 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1141,6 +1141,9 @@ struct buffer_head * breada(kdev_t dev, int block, int bufsize,
return NULL;
}
+/*
+ * Note: the caller should wake up the buffer_wait list if needed.
+ */
static void put_unused_buffer_head(struct buffer_head * bh)
{
if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS) {
@@ -1153,9 +1156,6 @@ static void put_unused_buffer_head(struct buffer_head * bh)
nr_unused_buffer_heads++;
bh->b_next_free = unused_list;
unused_list = bh;
- if (!waitqueue_active(&buffer_wait))
- return;
- wake_up(&buffer_wait);
}
/*
@@ -1165,18 +1165,26 @@ static void put_unused_buffer_head(struct buffer_head * bh)
* fields after the final unlock. So, the device driver puts them on
* the reuse_list instead once IO completes, and we recover these to
* the unused_list here.
+ *
+ * Note that we don't do a wakeup here, but return a flag indicating
+ * whether we got any buffer heads. A task ready to sleep can check
+ * the returned value, and any tasks already sleeping will have been
+ * awakened when the buffer heads were added to the reuse list.
*/
-static inline void recover_reusable_buffer_heads(void)
+static inline int recover_reusable_buffer_heads(void)
{
- struct buffer_head *head;
-
- head = xchg(&reuse_list, NULL);
+ struct buffer_head *head = xchg(&reuse_list, NULL);
+ int found = 0;
- while (head) {
- struct buffer_head *bh = head;
- head = head->b_next_free;
- put_unused_buffer_head(bh);
+ if (head) {
+ do {
+ struct buffer_head *bh = head;
+ head = head->b_next_free;
+ put_unused_buffer_head(bh);
+ } while (head);
+ found = 1;
}
+ return found;
}
/*
@@ -1275,11 +1283,15 @@ try_again:
* In case anything failed, we just free everything we got.
*/
no_grow:
- bh = head;
- while (bh) {
- head = bh;
- bh = bh->b_this_page;
- put_unused_buffer_head(head);
+ if (head) {
+ do {
+ bh = head;
+ head = head->b_this_page;
+ put_unused_buffer_head(bh);
+ } while (head);
+
+ /* Wake up any waiters ... */
+ wake_up(&buffer_wait);
}
/*
@@ -1305,8 +1317,8 @@ no_grow:
*/
add_wait_queue(&buffer_wait, &wait);
current->state = TASK_UNINTERRUPTIBLE;
- recover_reusable_buffer_heads();
- schedule();
+ if (!recover_reusable_buffer_heads())
+ schedule();
remove_wait_queue(&buffer_wait, &wait);
current->state = TASK_RUNNING;
goto try_again;
@@ -1323,6 +1335,8 @@ static inline void after_unlock_page (struct page * page)
atomic_read(&nr_async_pages));
#endif
}
+ if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
+ swap_after_unlock_page(page->offset);
if (test_and_clear_bit(PG_free_after, &page->flags))
__free_page(page);
}
@@ -1333,14 +1347,24 @@ static inline void after_unlock_page (struct page * page)
*/
static inline void free_async_buffers (struct buffer_head * bh)
{
- struct buffer_head * tmp;
+ struct buffer_head *tmp, *tail;
- tmp = bh;
- do {
- tmp->b_next_free = xchg(&reuse_list, NULL);
- reuse_list = tmp;
- tmp = tmp->b_this_page;
- } while (tmp != bh);
+ /*
+ * Link all the buffers into the b_next_free list,
+ * so we only have to do one xchg() operation ...
+ */
+ tail = bh;
+ while ((tmp = tail->b_this_page) != bh) {
+ tail->b_next_free = tmp;
+ tail = tmp;
+ };
+
+ /* Update the reuse list */
+ tail->b_next_free = xchg(&reuse_list, NULL);
+ reuse_list = bh;
+
+ /* Wake up any waiters ... */
+ wake_up(&buffer_wait);
}
static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
@@ -1390,7 +1414,6 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
after_unlock_page(page);
- wake_up(&buffer_wait);
return;
still_busy:
@@ -1636,6 +1659,7 @@ int try_to_free_buffer(struct buffer_head * bh, struct buffer_head ** bhp,
return 0;
tmp = tmp->b_this_page;
} while (tmp != bh);
+
tmp = bh;
do {
p = tmp;
@@ -1649,6 +1673,9 @@ int try_to_free_buffer(struct buffer_head * bh, struct buffer_head ** bhp,
remove_from_queues(p);
put_unused_buffer_head(p);
} while (tmp != bh);
+ /* Wake up anyone waiting for buffer heads */
+ wake_up(&buffer_wait);
+
buffermem -= PAGE_SIZE;
mem_map[MAP_NR(page)].buffers = NULL;
free_page(page);
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 96d07e265..92543a15c 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -161,9 +161,6 @@ static void coda_put_super(struct super_block *sb)
ENTRY;
- lock_super(sb);
-
- sb->s_dev = 0;
coda_cache_clear_all(sb);
sb_info = coda_sbp(sb);
sb_info->sbi_vcomm->vc_inuse = 0;
@@ -171,7 +168,6 @@ static void coda_put_super(struct super_block *sb)
printk("Coda: Bye bye.\n");
memset(sb_info, 0, sizeof(* sb_info));
- unlock_super(sb);
MOD_DEC_USE_COUNT;
EXIT;
}
diff --git a/fs/dcache.c b/fs/dcache.c
index 28cc277f5..58c6479c9 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -19,6 +19,8 @@
#include <linux/malloc.h>
#include <linux/init.h>
+#include <asm/uaccess.h>
+
#define DCACHE_PARANOIA 1
/* #define DCACHE_DEBUG 1 */
@@ -424,42 +426,16 @@ void shrink_dcache_parent(struct dentry * parent)
}
/*
- * This is called from do_try_to_free_page() to indicate
- * that we should reduce the dcache and inode cache memory.
+ * This is called from kswapd when we think we need some
+ * more memory, but aren't really sure how much. So we
+ * carefully try to free a _bit_ of our dcache, but not
+ * too much.
*/
-void shrink_dcache_memory()
+void shrink_dcache_memory(void)
{
- dentry_stat.want_pages++;
-}
-
-/*
- * This carries out the request received by the above routine.
- */
-void check_dcache_memory()
-{
- if (dentry_stat.want_pages) {
- unsigned int count, goal = 0;
- /*
- * Set the page goal. We don't necessarily need to trim
- * the dcache just because the system needs memory ...
- */
- if (page_cache_size > (num_physpages >> 1))
- goal = (dentry_stat.want_pages * page_cache_size)
- / num_physpages;
- dentry_stat.want_pages = 0;
- if (goal) {
- if (goal > 50)
- goal = 50;
- count = select_dcache(32, goal);
-#ifdef DCACHE_DEBUG
-printk(KERN_DEBUG "check_dcache_memory: goal=%d, count=%d\n", goal, count);
-#endif
- if (count) {
- prune_dcache(count);
- free_inode_memory(count);
- }
- }
- }
+ int count = select_dcache(32, 8);
+ if (count)
+ prune_dcache(count);
}
#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
@@ -669,7 +645,7 @@ void d_add(struct dentry * entry, struct inode * inode)
d_instantiate(entry, inode);
}
-#define switch(x,y) do { \
+#define do_switch(x,y) do { \
__typeof__ (x) __tmp = x; \
x = y; y = __tmp; } while (0)
@@ -705,10 +681,10 @@ void d_move(struct dentry * dentry, struct dentry * target)
list_del(&target->d_child);
/* Switch the parents and the names.. */
- switch(dentry->d_parent, target->d_parent);
- switch(dentry->d_name.name, target->d_name.name);
- switch(dentry->d_name.len, target->d_name.len);
- switch(dentry->d_name.hash, target->d_name.hash);
+ do_switch(dentry->d_parent, target->d_parent);
+ do_switch(dentry->d_name.name, target->d_name.name);
+ do_switch(dentry->d_name.len, target->d_name.len);
+ do_switch(dentry->d_name.hash, target->d_name.hash);
list_add(&target->d_child, &target->d_parent->d_subdirs);
list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
}
@@ -758,6 +734,51 @@ char * d_path(struct dentry *dentry, char *buffer, int buflen)
}
/*
+ * NOTE! The user-level library version returns a
+ * character pointer. The kernel system call just
+ * returns the length of the buffer filled (which
+ * includes the ending '\0' character), or a negative
+ * error value. So libc would do something like
+ *
+ * char *getcwd(char * buf, size_t size)
+ * {
+ * int retval;
+ *
+ * retval = sys_getcwd(buf, size);
+ * if (retval >= 0)
+ * return buf;
+ * errno = -retval;
+ * return NULL;
+ * }
+ */
+asmlinkage int sys_getcwd(char *buf, unsigned long size)
+{
+ int error;
+ struct dentry *pwd = current->fs->pwd;
+
+ error = -ENOENT;
+ /* Has the current directory has been unlinked? */
+ if (pwd->d_parent == pwd || !list_empty(&pwd->d_hash)) {
+ char *page = (char *) __get_free_page(GFP_USER);
+ error = -ENOMEM;
+ if (page) {
+ unsigned long len;
+ char * cwd = d_path(pwd, page, PAGE_SIZE);
+
+ error = -ERANGE;
+ len = PAGE_SIZE + page - cwd;
+ if (len <= size) {
+ error = len;
+ if (copy_to_user(buf, cwd, len))
+ error = -EFAULT;
+ }
+ free_page((unsigned long) page);
+ }
+ }
+ return error;
+}
+
+/*
* Test whether new_dentry is a subdirectory of old_dentry.
*
* Trivially implemented using the dcache structure
diff --git a/fs/devpts/.cvsignore b/fs/devpts/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/fs/devpts/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/fs/devpts/Makefile b/fs/devpts/Makefile
new file mode 100644
index 000000000..b8be35a4f
--- /dev/null
+++ b/fs/devpts/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the linux /dev/pts virtual filesystem.
+#
+
+O_TARGET := devpts.o
+O_OBJS := root.o inode.o
+
+M_OBJS := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff --git a/fs/devpts/devpts_i.h b/fs/devpts/devpts_i.h
new file mode 100644
index 000000000..03b6b0660
--- /dev/null
+++ b/fs/devpts/devpts_i.h
@@ -0,0 +1,42 @@
+/* -*- linux-c -*- --------------------------------------------------------- *
+ *
+ * linux/fs/devpts/devpts_i.h
+ *
+ * Copyright 1998 H. Peter Anvin -- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+
+#include <linux/fs.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+
+#define BUILDING_DEVPTS 1
+#include <linux/devpts_fs.h>
+
+struct devpts_sb_info {
+ u32 magic;
+ struct super_block *next;
+ struct super_block **back;
+ int setuid;
+ int setgid;
+ uid_t uid;
+ gid_t gid;
+ umode_t mode;
+
+ struct inode *inodes[NR_PTYS];
+};
+
+#define DEVPTS_SUPER_MAGIC 0x1cd1
+#define DEVPTS_SBI_MAGIC 0x01da1d02
+
+extern inline struct devpts_sb_info *SBI(struct super_block *sb)
+{
+ return (struct devpts_sb_info *)(sb->u.generic_sbp);
+}
+
+extern struct inode_operations devpts_root_inode_operations;
+extern struct inode_operations devpts_device_inode_operations;
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
new file mode 100644
index 000000000..54025e702
--- /dev/null
+++ b/fs/devpts/inode.c
@@ -0,0 +1,374 @@
+/* -*- linux-c -*- --------------------------------------------------------- *
+ *
+ * linux/fs/devpts/inode.c
+ *
+ * Copyright 1998 H. Peter Anvin -- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+
+#include <linux/module.h>
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kdev_t.h>
+#include <linux/kernel.h>
+#include <linux/locks.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/stat.h>
+#include <linux/tty.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+#include "devpts_i.h"
+
+static struct super_block *mounts = NULL;
+
+static void devpts_put_inode(struct inode *inode)
+{
+}
+
+static void devpts_delete_inode(struct inode *inode)
+{
+ inode->i_size = 0;
+}
+
+static void devpts_put_super(struct super_block *sb)
+{
+ struct devpts_sb_info *sbi = SBI(sb);
+ struct inode *inode;
+ int i;
+
+ for ( i = 0 ; i < NR_PTYS ; i++ ) {
+ if ( (inode = sbi->inodes[i]) ) {
+ if ( inode->i_count != 1 )
+ printk("devpts_put_super: badness: entry %d count %d\n",
+ i, inode->i_count);
+ iput(inode);
+ }
+ }
+
+ *sbi->back = sbi->next;
+ if ( sbi->next )
+ SBI(sbi->next)->back = sbi->back;
+
+ kfree(sbi);
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+static int devpts_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static void devpts_read_inode(struct inode *inode);
+static void devpts_write_inode(struct inode *inode);
+
+static struct super_operations devpts_sops = {
+ devpts_read_inode,
+ devpts_write_inode,
+ devpts_put_inode,
+ devpts_delete_inode,
+ NULL, /* notify_change */
+ devpts_put_super,
+ NULL, /* write_super */
+ devpts_statfs,
+ NULL, /* remount_fs */
+ NULL, /* clear_inode */
+};
+
+static int devpts_parse_options(char *options, struct devpts_sb_info *sbi)
+{
+ int setuid = 0;
+ int setgid = 0;
+ uid_t uid = 0; /* To shut up gcc */
+ gid_t gid = 0;
+ umode_t mode = 0600;
+ char *this_char, *value;
+
+ 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 1;
+ uid = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ setuid = 1;
+ }
+ else if (!strcmp(this_char,"gid")) {
+ if (!value || !*value)
+ return 1;
+ gid = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ setgid = 1;
+ }
+ else if (!strcmp(this_char,"mode")) {
+ if (!value || !*value)
+ return 1;
+ mode = simple_strtoul(value,&value,8);
+ if (*value)
+ return 1;
+ }
+ else
+ return 1;
+ }
+ sbi->setuid = setuid;
+ sbi->setgid = setgid;
+ sbi->uid = uid;
+ sbi->gid = gid;
+ sbi->mode = mode & ~S_IFMT;
+
+ return 0;
+}
+
+struct super_block *devpts_read_super(struct super_block *s, void *data,
+ int silent)
+{
+ struct inode * root_inode;
+ struct dentry * root;
+ struct devpts_sb_info *sbi;
+
+ MOD_INC_USE_COUNT;
+
+ lock_super(s);
+ /* Super block already completed? */
+ if (s->s_root)
+ goto out_unlock;
+
+ sbi = (struct devpts_sb_info *) kmalloc(sizeof(struct devpts_sb_info), GFP_KERNEL);
+ if ( !sbi )
+ goto fail_unlock;
+
+ sbi->magic = DEVPTS_SBI_MAGIC;
+ memset(sbi->inodes, 0, sizeof sbi->inodes);
+
+ s->u.generic_sbp = (void *) sbi;
+ s->s_blocksize = 1024;
+ s->s_blocksize_bits = 10;
+ s->s_magic = DEVPTS_SUPER_MAGIC;
+ s->s_op = &devpts_sops;
+ s->s_root = NULL;
+ unlock_super(s); /* shouldn't we keep it locked a while longer? */
+
+ /*
+ * Get the root inode and dentry, but defer checking for errors.
+ */
+ root_inode = iget(s, 1); /* inode 1 == root directory */
+ root = d_alloc_root(root_inode, NULL);
+
+ /*
+ * Check whether somebody else completed the super block.
+ */
+ if (s->s_root)
+ goto out_dput;
+
+ if (!root)
+ goto fail_iput;
+
+ /* Can this call block? (It shouldn't) */
+ if ( devpts_parse_options(data,sbi) ) {
+ printk("devpts: called with bogus options\n");
+ goto fail_dput;
+ }
+
+ /*
+ * Check whether somebody else completed the super block.
+ */
+ if (s->s_root)
+ goto out_dec;
+
+ /*
+ * Success! Install the root dentry now to indicate completion.
+ */
+ lock_super(s);
+ s->s_root = root;
+
+ sbi->next = mounts;
+ if ( sbi->next )
+ SBI(sbi->next)->back = &(sbi->next);
+ sbi->back = &mounts;
+ mounts = s;
+
+ unlock_super(s);
+ return s;
+
+ /*
+ * Success ... somebody else completed the super block for us.
+ */
+out_unlock:
+ unlock_super(s);
+ goto out_dec;
+out_dput:
+ if (root)
+ dput(root);
+ else
+ iput(root_inode);
+out_dec:
+ MOD_DEC_USE_COUNT;
+ return s;
+
+ /*
+ * Failure ... clear the s_dev slot and clean up.
+ */
+fail_dput:
+ /*
+ * dput() can block, so we clear the super block first.
+ */
+ s->s_dev = 0;
+ dput(root);
+ goto fail_free;
+fail_iput:
+ printk("devpts: get root dentry failed\n");
+ /*
+ * iput() can block, so we clear the super block first.
+ */
+ s->s_dev = 0;
+ iput(root_inode);
+fail_free:
+ kfree(sbi);
+ goto fail_dec;
+fail_unlock:
+ unlock_super(s);
+fail_dec:
+ s->s_dev = 0;
+ MOD_DEC_USE_COUNT;
+ return NULL;
+}
+
+static int devpts_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+{
+ struct statfs tmp;
+
+ tmp.f_type = DEVPTS_SUPER_MAGIC;
+ tmp.f_bsize = 1024;
+ 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;
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+}
+
+static void devpts_read_inode(struct inode *inode)
+{
+ ino_t ino = inode->i_ino;
+
+ inode->i_op = NULL;
+ inode->i_mode = 0;
+ inode->i_nlink = 0;
+ inode->i_size = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_blocks = 0;
+ inode->i_blksize = 1024;
+ inode->i_uid = inode->i_gid = 0;
+
+ if ( ino == 1 ) {
+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
+ inode->i_op = &devpts_root_inode_operations;
+ inode->i_nlink = 2;
+ return;
+ }
+
+ ino -= 2;
+ if ( ino >= NR_PTYS )
+ return; /* Bogus */
+
+ inode->i_nlink = 1;
+
+ inode->i_mode = S_IFCHR;
+ inode->i_rdev = MKDEV(0,0); /* Gets filled in by devpts_pty_new() */
+
+ inode->i_op = &chrdev_inode_operations;
+
+ return;
+}
+
+static void devpts_write_inode(struct inode *inode)
+{
+}
+
+static struct file_system_type devpts_fs_type = {
+ "devpts",
+ 0,
+ devpts_read_super,
+ NULL
+};
+
+void devpts_pty_new(int number, kdev_t device)
+{
+ struct super_block *sb;
+ struct devpts_sb_info *sbi;
+ struct inode *inode;
+
+ for ( sb = mounts ; sb ; sb = sbi->next ) {
+ sbi = SBI(sb);
+
+ if ( sbi->inodes[number] ) {
+ continue; /* Already registered, this does happen */
+ }
+
+ /* Yes, this looks backwards, but it is correct */
+ inode = iget(sb, number+2);
+ if ( inode ) {
+ inode->i_uid = sbi->setuid ? sbi->uid : current->fsuid;
+ inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid;
+ inode->i_mode = sbi->mode | S_IFCHR;
+ inode->i_rdev = device;
+ sbi->inodes[number] = inode;
+ }
+ }
+}
+
+void devpts_pty_kill(int number)
+{
+ struct super_block *sb;
+ struct devpts_sb_info *sbi;
+ struct inode *inode;
+
+ for ( sb = mounts ; sb ; sb = sbi->next ) {
+ sbi = SBI(sb);
+
+ inode = sbi->inodes[number];
+
+ if ( inode ) {
+ sbi->inodes[number] = NULL;
+ inode->i_nlink = 0; /* Is this right? */
+ iput(inode);
+ }
+ }
+}
+
+__initfunc(int init_devpts_fs(void))
+{
+ return register_filesystem(&devpts_fs_type);
+
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+ int err = init_devpts_fs();
+ if ( !err ) {
+ devpts_upcall_new = devpts_pty_new;
+ devpts_upcall_kill = devpts_pty_kill;
+ }
+ return err;
+}
+
+void cleanup_module(void)
+{
+ devpts_upcall_new = NULL;
+ devpts_upcall_kill = NULL;
+ unregister_filesystem(&devpts_fs_type);
+}
+
+#endif
diff --git a/fs/devpts/root.c b/fs/devpts/root.c
new file mode 100644
index 000000000..1ee855bb4
--- /dev/null
+++ b/fs/devpts/root.c
@@ -0,0 +1,170 @@
+/* -*- linux-c -*- --------------------------------------------------------- *
+ *
+ * linux/fs/devpts/root.c
+ *
+ * Copyright 1998 H. Peter Anvin -- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+
+#include <linux/errno.h>
+#include <linux/stat.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include "devpts_i.h"
+
+static int devpts_root_readdir(struct file *,void *,filldir_t);
+static int devpts_root_lookup(struct inode *,struct dentry *);
+static int devpts_revalidate(struct dentry *);
+
+static struct file_operations devpts_root_operations = {
+ NULL, /* llseek */
+ NULL, /* read */
+ NULL, /* write */
+ devpts_root_readdir, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* open */
+ NULL, /* release */
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
+};
+
+struct inode_operations devpts_root_inode_operations = {
+ &devpts_root_operations, /* file operations */
+ NULL, /* create */
+ devpts_root_lookup, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL /* revalidate */
+};
+
+static struct dentry_operations devpts_dentry_operations = {
+ devpts_revalidate, /* d_revalidate */
+ NULL, /* d_hash */
+ NULL, /* d_compare */
+};
+
+/*
+ * The normal naming convention is simply /dev/pts/<number>; this conforms
+ * to the System V naming convention
+ */
+
+#define genptsname(buf,num) sprintf(buf, "%d", num)
+
+static int devpts_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ struct inode * inode = filp->f_dentry->d_inode;
+ struct devpts_sb_info * sbi = SBI(filp->f_dentry->d_inode->i_sb);
+ off_t nr;
+ char numbuf[16];
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -ENOTDIR;
+
+ nr = filp->f_pos;
+
+ switch(nr)
+ {
+ case 0:
+ if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ case 1:
+ if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ default:
+ while ( nr < NR_PTYS+2 ) {
+ int ptynr = nr - 2;
+ if ( sbi->inodes[ptynr] ) {
+ genptsname(numbuf, ptynr);
+ if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 )
+ return 0;
+ }
+ filp->f_pos = ++nr;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Revalidate is called on every cache lookup. We use it to check that
+ * the pty really does still exist. Never revalidate negative dentries;
+ * for simplicity (fix later?)
+ */
+static int devpts_revalidate(struct dentry * dentry)
+{
+ struct devpts_sb_info *sbi;
+
+ if ( !dentry->d_inode )
+ return 0;
+
+ sbi = SBI(dentry->d_inode->i_sb);
+
+ return ( sbi->inodes[dentry->d_inode->i_ino - 2] == dentry->d_inode );
+}
+
+static int devpts_root_lookup(struct inode * dir, struct dentry * dentry)
+{
+ struct devpts_sb_info *sbi = SBI(dir->i_sb);
+ int entry, i;
+ const char *p;
+
+ if (!S_ISDIR(dir->i_mode))
+ return -ENOTDIR;
+
+ dentry->d_inode = NULL; /* Assume failure */
+ dentry->d_op = &devpts_dentry_operations;
+
+ if ( dentry->d_name.len == 1 && dentry->d_name.name[0] == '0' ) {
+ entry = 0;
+ } else if ( dentry->d_name.len < 1 ) {
+ return 0;
+ } else {
+ p = dentry->d_name.name;
+ if ( *p < '1' || *p > '9' )
+ return 0;
+ entry = *p++ - '0';
+
+ for ( i = dentry->d_name.len-1 ; i ; i-- ) {
+ if ( *p < '0' || *p > '9' )
+ return 0;
+ entry *= 10;
+ entry += (*p++ - '0');
+ }
+ }
+
+ dentry->d_inode = sbi->inodes[entry];
+ if ( dentry->d_inode )
+ dentry->d_inode->i_count++;
+
+ d_add(dentry, dentry->d_inode);
+
+ return 0;
+}
diff --git a/fs/exec.c b/fs/exec.c
index f67c028ff..0ad7c4cdf 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -609,6 +609,45 @@ int prepare_binprm(struct linux_binprm *bprm)
id_change = 1;
}
+ /* We don't have VFS support for capabilities yet */
+ cap_clear(bprm->cap_inheritable);
+ cap_clear(bprm->cap_permitted);
+ cap_clear(bprm->cap_effective);
+
+ /* To support inheritance of root-permissions and suid-root
+ * executables under compatibility mode, we raise the
+ * effective and inherited bitmasks of the executable file
+ * (translation: we set the executable "capability dumb" and
+ * set the allowed set to maximum). We don't set any forced
+ * bits.
+ *
+ * If only the real uid is 0, we only raise the inheritable
+ * bitmask of the executable file (translation: we set the
+ * allowed set to maximum and the application to "capability
+ * smart").
+ */
+
+ if (!issecure(SECURE_NOROOT)) {
+ if (bprm->e_uid == 0 || current->uid == 0)
+ cap_set_full(bprm->cap_inheritable);
+ if (bprm->e_uid == 0)
+ cap_set_full(bprm->cap_effective);
+ }
+
+ /* We use a conservative definition of suid for capabilities.
+ * The process is suid if the permitted set is not a subset of
+ * the current permitted set after the exec call.
+ * new permitted set = forced | (allowed & inherited)
+ * pP' = fP | (fI & pI)
+ */
+
+ if ((bprm->cap_permitted.cap |
+ (current->cap_inheritable.cap &
+ bprm->cap_inheritable.cap)) &
+ ~current->cap_permitted.cap) {
+ id_change = 1;
+ }
+
if (id_change) {
/* We can't suid-execute if we're sharing parts of the executable */
/* or if we're being traced (or if suid execs are not allowed) */
@@ -627,6 +666,38 @@ int prepare_binprm(struct linux_binprm *bprm)
return read_exec(bprm->dentry,0,bprm->buf,128,1);
}
+/*
+ * This function is used to produce the new IDs and capabilities
+ * from the old ones and the file's capabilities.
+ *
+ * The formula used for evolving capabilities is:
+ *
+ * pI' = pI
+ * pP' = fP | (fI & pI)
+ * pE' = pP' & fE [NB. fE is 0 or ~0]
+ *
+ * I=Inheritable, P=Permitted, E=Effective // p=process, f=file
+ * ' indicates post-exec().
+ */
+
+void compute_creds(struct linux_binprm *bprm)
+{
+ int new_permitted = bprm->cap_permitted.cap |
+ (bprm->cap_inheritable.cap & current->cap_inheritable.cap);
+
+ current->cap_permitted.cap = new_permitted;
+ current->cap_effective.cap = new_permitted & bprm->cap_effective.cap;
+
+ /* AUD: Audit candidate if current->cap_effective is set */
+
+ current->suid = current->euid = current->fsuid = bprm->e_uid;
+ current->sgid = current->egid = current->fsgid = bprm->e_gid;
+ if (current->euid != current->uid || current->egid != current->gid ||
+ !cap_isclear(current->cap_permitted))
+ current->dumpable = 0;
+}
+
+
void remove_arg_zero(struct linux_binprm *bprm)
{
if (bprm->argc) {
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 4f2e65bfc..de5b422ed 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -38,27 +38,33 @@
#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
-static struct ext2_group_desc * get_group_desc (struct super_block * sb,
- unsigned int block_group,
- struct buffer_head ** bh)
+struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
+ unsigned int block_group,
+ struct buffer_head ** bh)
{
unsigned long group_desc;
unsigned long desc;
struct ext2_group_desc * gdp;
- if (block_group >= sb->u.ext2_sb.s_groups_count)
- ext2_panic (sb, "get_group_desc",
+ if (block_group >= sb->u.ext2_sb.s_groups_count) {
+ ext2_error (sb, "ext2_get_group_desc",
"block_group >= groups_count - "
"block_group = %d, groups_count = %lu",
block_group, sb->u.ext2_sb.s_groups_count);
+ return NULL;
+ }
+
group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
desc = block_group % EXT2_DESC_PER_BLOCK(sb);
- if (!sb->u.ext2_sb.s_group_desc[group_desc])
- ext2_panic (sb, "get_group_desc",
+ if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
+ ext2_error (sb, "ext2_get_group_desc",
"Group descriptor not loaded - "
"block_group = %d, group_desc = %lu, desc = %lu",
block_group, group_desc, desc);
+ return NULL;
+ }
+
gdp = (struct ext2_group_desc *)
sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
if (bh)
@@ -66,22 +72,40 @@ static struct ext2_group_desc * get_group_desc (struct super_block * sb,
return gdp + desc;
}
-static void read_block_bitmap (struct super_block * sb,
+/*
+ * Read the bitmap for a given block_group, reading into the specified
+ * slot in the superblock's bitmap cache.
+ *
+ * Return >=0 on success or a -ve error code.
+ */
+
+static int read_block_bitmap (struct super_block * sb,
unsigned int block_group,
unsigned long bitmap_nr)
{
struct ext2_group_desc * gdp;
- struct buffer_head * bh;
+ struct buffer_head * bh = NULL;
+ int retval = 0;
- gdp = get_group_desc (sb, block_group, NULL);
+ gdp = ext2_get_group_desc (sb, block_group, NULL);
+ if (!gdp)
+ goto error_out;
bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_block_bitmap), sb->s_blocksize);
- if (!bh)
- ext2_panic (sb, "read_block_bitmap",
+ if (!bh) {
+ ext2_error (sb, "read_block_bitmap",
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %lu",
- block_group, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap));
+ block_group, (unsigned long) gdp->bg_block_bitmap);
+ retval = -EIO;
+ }
+ /*
+ * On IO error, just leave a zero in the superblock's block pointer for
+ * this group. The IO will be retried next time.
+ */
+error_out:
sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group;
sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh;
+ return retval;
}
/*
@@ -94,11 +118,13 @@ static void read_block_bitmap (struct super_block * sb,
* 1/ There is one cache per mounted file system.
* 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
* this function reads the bitmap without maintaining a LRU cache.
+ *
+ * Return the slot used to store the bitmap, or a -ve error code.
*/
static int load__block_bitmap (struct super_block * sb,
unsigned int block_group)
{
- int i, j;
+ int i, j, retval = 0;
unsigned long block_bitmap_number;
struct buffer_head * block_bitmap;
@@ -110,16 +136,16 @@ static int load__block_bitmap (struct super_block * sb,
if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
if (sb->u.ext2_sb.s_block_bitmap[block_group]) {
- if (sb->u.ext2_sb.s_block_bitmap_number[block_group] !=
+ if (sb->u.ext2_sb.s_block_bitmap_number[block_group] ==
block_group)
- ext2_panic (sb, "load_block_bitmap",
- "block_group != block_bitmap_number");
- else
return block_group;
- } else {
- read_block_bitmap (sb, block_group, block_group);
- return block_group;
+ ext2_error (sb, "load_block_bitmap",
+ "block_group != block_bitmap_number");
}
+ retval = read_block_bitmap (sb, block_group, block_group);
+ if (retval < 0)
+ return retval;
+ return block_group;
}
for (i = 0; i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
@@ -137,6 +163,14 @@ static int load__block_bitmap (struct super_block * sb,
}
sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number;
sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap;
+
+ /*
+ * There's still one special case here --- if block_bitmap == 0
+ * then our last attempt to read the bitmap failed and we have
+ * just ended up caching that failure. Try again to read it.
+ */
+ if (!block_bitmap)
+ retval = read_block_bitmap (sb, block_group, 0);
} else {
if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
sb->u.ext2_sb.s_loaded_block_bitmaps++;
@@ -148,24 +182,71 @@ static int load__block_bitmap (struct super_block * sb,
sb->u.ext2_sb.s_block_bitmap[j] =
sb->u.ext2_sb.s_block_bitmap[j - 1];
}
- read_block_bitmap (sb, block_group, 0);
+ retval = read_block_bitmap (sb, block_group, 0);
}
- return 0;
+ return retval;
}
+/*
+ * Load the block bitmap for a given block group. First of all do a couple
+ * of fast lookups for common cases and then pass the request onto the guts
+ * of the bitmap loader.
+ *
+ * Return the slot number of the group in the superblock bitmap cache's on
+ * success, or a -ve error code.
+ *
+ * There is still one inconsistancy here --- if the number of groups in this
+ * filesystems is <= EXT2_MAX_GROUP_LOADED, then we have no way of
+ * differentiating between a group for which we have never performed a bitmap
+ * IO request, and a group for which the last bitmap read request failed.
+ */
static inline int load_block_bitmap (struct super_block * sb,
unsigned int block_group)
{
- if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 &&
- sb->u.ext2_sb.s_block_bitmap_number[0] == block_group)
- return 0;
+ int slot;
- if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED &&
- sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group &&
- sb->u.ext2_sb.s_block_bitmap[block_group])
- return block_group;
+ /*
+ * Do the lookup for the slot. First of all, check if we're asking
+ * for the same slot as last time, and did we succeed that last time?
+ */
+ if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 &&
+ sb->u.ext2_sb.s_block_bitmap_number[0] == block_group &&
+ sb->u.ext2_sb.s_block_bitmap[block_group]) {
+ slot = 0;
+ }
+ /*
+ * Or can we do a fast lookup based on a loaded group on a filesystem
+ * small enough to be mapped directly into the superblock?
+ */
+ else if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED &&
+ sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group &&
+ sb->u.ext2_sb.s_block_bitmap[block_group]) {
+ slot = block_group;
+ }
+ /*
+ * If not, then do a full lookup for this block group.
+ */
+ else {
+ slot = load__block_bitmap (sb, block_group);
+ }
- return load__block_bitmap (sb, block_group);
+ /*
+ * <0 means we just got an error
+ */
+ if (slot < 0)
+ return slot;
+
+ /*
+ * If it's a valid slot, we may still have cached a previous IO error,
+ * in which case the bh in the superblock cache will be zero.
+ */
+ if (!sb->u.ext2_sb.s_block_bitmap[slot])
+ return -EIO;
+
+ /*
+ * Must have been read in OK to get this far.
+ */
+ return slot;
}
void ext2_free_blocks (const struct inode * inode, unsigned long block,
@@ -194,8 +275,7 @@ void ext2_free_blocks (const struct inode * inode, unsigned long block,
ext2_error (sb, "ext2_free_blocks",
"Freeing blocks not in datazone - "
"block = %lu, count = %lu", block, count);
- unlock_super (sb);
- return;
+ goto error_return;
}
ext2_debug ("freeing block %lu\n", block);
@@ -215,8 +295,13 @@ do_more:
count -= overflow;
}
bitmap_nr = load_block_bitmap (sb, block_group);
+ if (bitmap_nr < 0)
+ goto error_return;
+
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
- gdp = get_group_desc (sb, block_group, &bh2);
+ gdp = ext2_get_group_desc (sb, block_group, &bh2);
+ if (!gdp)
+ goto error_return;
if (test_opt (sb, CHECK_STRICT) &&
(in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) ||
@@ -259,6 +344,7 @@ do_more:
goto do_more;
}
sb->s_dirt = 1;
+error_return:
unlock_super (sb);
return;
}
@@ -312,7 +398,10 @@ repeat:
goal >= le32_to_cpu(es->s_blocks_count))
goal = le32_to_cpu(es->s_first_data_block);
i = (goal - le32_to_cpu(es->s_first_data_block)) / EXT2_BLOCKS_PER_GROUP(sb);
- gdp = get_group_desc (sb, i, &bh2);
+ gdp = ext2_get_group_desc (sb, i, &bh2);
+ if (!gdp)
+ goto io_error;
+
if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) {
j = ((goal - le32_to_cpu(es->s_first_data_block)) % EXT2_BLOCKS_PER_GROUP(sb));
#ifdef EXT2FS_DEBUG
@@ -320,6 +409,9 @@ repeat:
goal_attempts++;
#endif
bitmap_nr = load_block_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ goto io_error;
+
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
ext2_debug ("goal is at %d:%d.\n", i, j);
@@ -384,7 +476,12 @@ repeat:
i++;
if (i >= sb->u.ext2_sb.s_groups_count)
i = 0;
- gdp = get_group_desc (sb, i, &bh2);
+ gdp = ext2_get_group_desc (sb, i, &bh2);
+ if (!gdp) {
+ *err = -EIO;
+ unlock_super (sb);
+ return 0;
+ }
if (le16_to_cpu(gdp->bg_free_blocks_count) > 0)
break;
}
@@ -393,6 +490,9 @@ repeat:
return 0;
}
bitmap_nr = load_block_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ goto io_error;
+
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
r = memscan(bh->b_data, 0, EXT2_BLOCKS_PER_GROUP(sb) >> 3);
j = (r - bh->b_data) << 3;
@@ -455,10 +555,16 @@ got_block:
*/
#ifdef EXT2_PREALLOCATE
if (prealloc_block) {
+ int prealloc_goal;
+
+ prealloc_goal = es->s_prealloc_blocks ?
+ es->s_prealloc_blocks : EXT2_DEFAULT_PREALLOC_BLOCKS;
+
*prealloc_count = 0;
*prealloc_block = tmp + 1;
for (k = 1;
- k < 8 && (j + k) < EXT2_BLOCKS_PER_GROUP(sb); k++) {
+ k < prealloc_goal && (j + k) < EXT2_BLOCKS_PER_GROUP(sb);
+ k++) {
if (sb->dq_op)
if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(1, sb->s_blocksize)))
break;
@@ -516,6 +622,12 @@ got_block:
unlock_super (sb);
*err = 0;
return j;
+
+io_error:
+ *err = -EIO;
+ unlock_super (sb);
+ return 0;
+
}
unsigned long ext2_count_free_blocks (struct super_block * sb)
@@ -533,9 +645,14 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
bitmap_count = 0;
gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
- gdp = get_group_desc (sb, i, NULL);
+ gdp = ext2_get_group_desc (sb, i, NULL);
+ if (!gdp)
+ continue;
desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
bitmap_nr = load_block_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ continue;
+
x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
sb->s_blocksize);
printk ("group %d: stored = %d, counted = %lu\n",
@@ -590,12 +707,17 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
desc_blocks = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
EXT2_DESC_PER_BLOCK(sb);
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
- gdp = get_group_desc (sb, i, NULL);
+ gdp = ext2_get_group_desc (sb, i, NULL);
+ if (!gdp)
+ continue;
desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
bitmap_nr = load_block_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ continue;
+
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
- if (!(sb->u.ext2_sb.s_feature_ro_compat &
+ if (!(le32_to_cpu(sb->u.ext2_sb.s_feature_ro_compat) &
EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
(test_root(i, 3) || test_root(i, 5) || test_root(i, 7))) {
if (!ext2_test_bit (0, bh->b_data))
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 6560d511d..19241876d 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -75,7 +75,8 @@ struct inode_operations ext2_dir_inode_operations = {
};
int ext2_check_dir_entry (const char * function, struct inode * dir,
- struct ext2_dir_entry * de, struct buffer_head * bh,
+ struct ext2_dir_entry_2 * de,
+ struct buffer_head * bh,
unsigned long offset)
{
const char * error_msg = NULL;
@@ -84,7 +85,7 @@ int ext2_check_dir_entry (const char * function, struct inode * dir,
error_msg = "rec_len is smaller than minimal";
else if (le16_to_cpu(de->rec_len) % 4 != 0)
error_msg = "rec_len % 4 != 0";
- else if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len)))
+ else if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(de->name_len))
error_msg = "rec_len is too small for name_len";
else if (dir && ((char *) de - bh->b_data) + le16_to_cpu(de->rec_len) >
dir->i_sb->s_blocksize)
@@ -97,7 +98,7 @@ int ext2_check_dir_entry (const char * function, struct inode * dir,
"offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
dir->i_ino, error_msg, offset,
(unsigned long) le32_to_cpu(de->inode),
- le16_to_cpu(de->rec_len), le16_to_cpu(de->name_len));
+ le16_to_cpu(de->rec_len), de->name_len);
return error_msg == NULL ? 1 : 0;
}
@@ -108,7 +109,7 @@ static int ext2_readdir(struct file * filp,
unsigned long offset, blk;
int i, num, stored;
struct buffer_head * bh, * tmp, * bha[16];
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
struct super_block * sb;
int err;
struct inode *inode = filp->f_dentry->d_inode;
@@ -158,7 +159,7 @@ revalidate:
* to make sure. */
if (filp->f_version != inode->i_version) {
for (i = 0; i < sb->s_blocksize && i < offset; ) {
- de = (struct ext2_dir_entry *)
+ de = (struct ext2_dir_entry_2 *)
(bh->b_data + i);
/* It's too expensive to do a full
* dirent test each time round this
@@ -178,7 +179,7 @@ revalidate:
while (!error && filp->f_pos < inode->i_size
&& offset < sb->s_blocksize) {
- de = (struct ext2_dir_entry *) (bh->b_data + offset);
+ de = (struct ext2_dir_entry_2 *) (bh->b_data + offset);
if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
bh, offset)) {
/* On error, skip the f_pos to the
@@ -200,7 +201,7 @@ revalidate:
unsigned long version = inode->i_version;
error = filldir(dirent, de->name,
- le16_to_cpu(de->name_len),
+ de->name_len,
filp->f_pos, le32_to_cpu(de->inode));
if (error)
break;
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 9c61f2f1c..143dc53d5 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -13,6 +13,9 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*
* ext2 fs regular file handling primitives
+ *
+ * 64-bit file support on 64-bit platforms by Jakub Jelinek
+ * (jj@sunsite.ms.mff.cuni.cz)
*/
#include <asm/uaccess.h>
@@ -36,6 +39,23 @@
static long long ext2_file_lseek(struct file *, long long, int);
static ssize_t ext2_file_write (struct file *, const char *, size_t, loff_t *);
static int ext2_release_file (struct inode *, struct file *);
+#if BITS_PER_LONG < 64
+static int ext2_open_file (struct inode *, struct file *);
+
+#else
+
+#define EXT2_MAX_SIZE(bits) \
+ (((EXT2_NDIR_BLOCKS + (1LL << (bits - 2)) + \
+ (1LL << (bits - 2)) * (1LL << (bits - 2)) + \
+ (1LL << (bits - 2)) * (1LL << (bits - 2)) * (1LL << (bits - 2))) * \
+ (1LL << bits)) - 1)
+
+static long long ext2_max_sizes[] = {
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+EXT2_MAX_SIZE(10), EXT2_MAX_SIZE(11), EXT2_MAX_SIZE(12), EXT2_MAX_SIZE(13)
+};
+
+#endif
/*
* We have mostly NULL's here: the current defaults are ok for
@@ -49,7 +69,11 @@ static struct file_operations ext2_file_operations = {
NULL, /* poll - default */
ext2_ioctl, /* ioctl */
generic_file_mmap, /* mmap */
+#if BITS_PER_LONG == 64
NULL, /* no special open is needed */
+#else
+ ext2_open_file,
+#endif
ext2_release_file, /* release */
ext2_sync_file, /* fsync */
NULL, /* fasync */
@@ -86,7 +110,6 @@ static long long ext2_file_lseek(
long long offset,
int origin)
{
- long long retval;
struct inode *inode = file->f_dentry->d_inode;
switch (origin) {
@@ -96,17 +119,20 @@ static long long ext2_file_lseek(
case 1:
offset += file->f_pos;
}
- retval = -EINVAL;
- /* make sure the offset fits in 32 bits */
- if (((unsigned long long) offset >> 32) == 0) {
- if (offset != file->f_pos) {
- file->f_pos = offset;
- file->f_reada = 0;
- file->f_version = ++event;
- }
- retval = offset;
+ if (((unsigned long long) offset >> 32) != 0) {
+#if BITS_PER_LONG < 64
+ return -EINVAL;
+#else
+ if (offset > ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(inode->i_sb)])
+ return -EINVAL;
+#endif
+ }
+ if (offset != file->f_pos) {
+ file->f_pos = offset;
+ file->f_reada = 0;
+ file->f_version = ++event;
}
- return retval;
+ return offset;
}
static inline void remove_suid(struct inode *inode)
@@ -128,7 +154,7 @@ static ssize_t ext2_file_write (struct file * filp, const char * buf,
size_t count, loff_t *ppos)
{
struct inode * inode = filp->f_dentry->d_inode;
- __u32 pos;
+ off_t pos;
long block;
int offset;
int written, c;
@@ -165,14 +191,39 @@ static ssize_t ext2_file_write (struct file * filp, const char * buf,
pos = *ppos;
if (pos != *ppos)
return -EINVAL;
+#if BITS_PER_LONG >= 64
+ if (pos > ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(sb)])
+ return -EINVAL;
+#endif
}
/* Check for overflow.. */
+#if BITS_PER_LONG < 64
if (pos > (__u32) (pos + count)) {
count = ~pos; /* == 0xFFFFFFFF - pos */
if (!count)
return -EFBIG;
}
+#else
+ {
+ off_t max = ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(sb)];
+
+ if (pos + count > max) {
+ count = max - pos;
+ if (!count)
+ return -EFBIG;
+ }
+ if (((pos + count) >> 32) &&
+ !(sb->u.ext2_sb.s_es->s_feature_ro_compat &
+ cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE))) {
+ /* If this is the first large file created, add a flag
+ to the superblock */
+ sb->u.ext2_sb.s_es->s_feature_ro_compat |=
+ cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
+ mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+ }
+ }
+#endif
/*
* If a file has been opened in synchronous mode, we have to ensure
@@ -219,6 +270,11 @@ static ssize_t ext2_file_write (struct file * filp, const char * buf,
count -= c;
mark_buffer_uptodate(bh, 1);
mark_buffer_dirty(bh, 0);
+
+ /* Mark the buffer untouched if we'll move on to the next one.. */
+ if (!(pos & (sb->s_blocksize-1)))
+ clear_bit(BH_Touched, &bh->b_state);
+
if (filp->f_flags & O_SYNC)
bufferlist[buffercount++] = bh;
else
@@ -260,12 +316,25 @@ static ssize_t ext2_file_write (struct file * filp, const char * buf,
/*
* Called when an inode is released. Note that this is different
- * from ext2_open: open gets called at every open, but release
+ * from ext2_file_open: open gets called at every open, but release
* gets called only when /all/ the files are closed.
*/
static int ext2_release_file (struct inode * inode, struct file * filp)
{
- if (filp->f_mode & 2)
+ if (filp->f_mode & FMODE_WRITE)
ext2_discard_prealloc (inode);
return 0;
}
+
+#if BITS_PER_LONG < 64
+/*
+ * Called when an inode is about to be open.
+ * We use this to disallow opening RW large files on 32bit systems.
+ */
+static int ext2_open_file (struct inode * inode, struct file * filp)
+{
+ if (inode->u.ext2_i.i_high_size && (filp->f_mode & FMODE_WRITE))
+ return -EFBIG;
+ return 0;
+}
+#endif
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 61288535e..0335eaacd 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -37,50 +37,41 @@
#include <asm/bitops.h>
#include <asm/byteorder.h>
-static struct ext2_group_desc * get_group_desc (struct super_block * sb,
- unsigned int block_group,
- struct buffer_head ** bh)
-{
- unsigned long group_desc;
- unsigned long desc;
- struct ext2_group_desc * gdp;
-
- if (block_group >= sb->u.ext2_sb.s_groups_count)
- ext2_panic (sb, "get_group_desc",
- "block_group >= groups_count - "
- "block_group = %d, groups_count = %lu",
- block_group, sb->u.ext2_sb.s_groups_count);
-
- group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
- desc = block_group % EXT2_DESC_PER_BLOCK(sb);
- if (!sb->u.ext2_sb.s_group_desc[group_desc])
- ext2_panic (sb, "get_group_desc",
- "Group descriptor not loaded - "
- "block_group = %d, group_desc = %lu, desc = %lu",
- block_group, group_desc, desc);
- gdp = (struct ext2_group_desc *)
- sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
- if (bh)
- *bh = sb->u.ext2_sb.s_group_desc[group_desc];
- return gdp + desc;
-}
-
-static void read_inode_bitmap (struct super_block * sb,
+/*
+ * Read the inode allocation bitmap for a given block_group, reading
+ * into the specified slot in the superblock's bitmap cache.
+ *
+ * Return >=0 on success or a -ve error code.
+ */
+static int read_inode_bitmap (struct super_block * sb,
unsigned long block_group,
unsigned int bitmap_nr)
{
struct ext2_group_desc * gdp;
- struct buffer_head * bh;
+ struct buffer_head * bh = NULL;
+ int retval = 0;
- gdp = get_group_desc (sb, block_group, NULL);
+ gdp = ext2_get_group_desc (sb, block_group, NULL);
+ if (!gdp) {
+ retval = -EIO;
+ goto error_out;
+ }
bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_inode_bitmap), sb->s_blocksize);
- if (!bh)
- ext2_panic (sb, "read_inode_bitmap",
+ if (!bh) {
+ ext2_error (sb, "read_inode_bitmap",
"Cannot read inode bitmap - "
"block_group = %lu, inode_bitmap = %lu",
- block_group, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap));
+ block_group, (unsigned long) gdp->bg_inode_bitmap);
+ retval = -EIO;
+ }
+ /*
+ * On IO error, just leave a zero in the superblock's block pointer for
+ * this group. The IO will be retried next time.
+ */
+error_out:
sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group;
sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh;
+ return retval;
}
/*
@@ -93,11 +84,13 @@ static void read_inode_bitmap (struct super_block * sb,
* 1/ There is one cache per mounted file system.
* 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
* this function reads the bitmap without maintaining a LRU cache.
+ *
+ * Return the slot used to store the bitmap, or a -ve error code.
*/
static int load_inode_bitmap (struct super_block * sb,
unsigned int block_group)
{
- int i, j;
+ int i, j, retval = 0;
unsigned long inode_bitmap_number;
struct buffer_head * inode_bitmap;
@@ -117,7 +110,10 @@ static int load_inode_bitmap (struct super_block * sb,
else
return block_group;
} else {
- read_inode_bitmap (sb, block_group, block_group);
+ retval = read_inode_bitmap (sb, block_group,
+ block_group);
+ if (retval < 0)
+ return retval;
return block_group;
}
}
@@ -138,6 +134,15 @@ static int load_inode_bitmap (struct super_block * sb,
}
sb->u.ext2_sb.s_inode_bitmap_number[0] = inode_bitmap_number;
sb->u.ext2_sb.s_inode_bitmap[0] = inode_bitmap;
+
+ /*
+ * There's still one special case here --- if inode_bitmap == 0
+ * then our last attempt to read the bitmap failed and we have
+ * just ended up caching that failure. Try again to read it.
+ */
+ if (!inode_bitmap)
+ retval = read_inode_bitmap (sb, block_group, 0);
+
} else {
if (sb->u.ext2_sb.s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED)
sb->u.ext2_sb.s_loaded_inode_bitmaps++;
@@ -149,9 +154,9 @@ static int load_inode_bitmap (struct super_block * sb,
sb->u.ext2_sb.s_inode_bitmap[j] =
sb->u.ext2_sb.s_inode_bitmap[j - 1];
}
- read_inode_bitmap (sb, block_group, 0);
+ retval = read_inode_bitmap (sb, block_group, 0);
}
- return 0;
+ return retval;
}
/*
@@ -212,13 +217,15 @@ void ext2_free_inode (struct inode * inode)
ino > le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count)) {
ext2_error (sb, "free_inode",
"reserved inode or nonexistent inode");
- unlock_super (sb);
- return;
+ goto error_return;
}
es = sb->u.ext2_sb.s_es;
block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb);
bit = (ino - 1) % EXT2_INODES_PER_GROUP(sb);
bitmap_nr = load_inode_bitmap (sb, block_group);
+ if (bitmap_nr < 0)
+ goto error_return;
+
bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
is_directory = S_ISDIR(inode->i_mode);
@@ -233,12 +240,14 @@ void ext2_free_inode (struct inode * inode)
ext2_warning (sb, "ext2_free_inode",
"bit already cleared for inode %lu", ino);
else {
- gdp = get_group_desc (sb, block_group, &bh2);
- gdp->bg_free_inodes_count =
- cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) + 1);
- if (is_directory)
- gdp->bg_used_dirs_count =
- cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1);
+ gdp = ext2_get_group_desc (sb, block_group, &bh2);
+ if (gdp) {
+ gdp->bg_free_inodes_count =
+ cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) + 1);
+ if (is_directory)
+ gdp->bg_used_dirs_count =
+ cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1);
+ }
mark_buffer_dirty(bh2, 1);
es->s_free_inodes_count =
cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1);
@@ -250,6 +259,7 @@ void ext2_free_inode (struct inode * inode)
wait_on_buffer (bh);
}
sb->s_dirt = 1;
+error_return:
unlock_super (sb);
}
@@ -317,9 +327,10 @@ repeat:
/* I am not yet convinced that this next bit is necessary.
i = dir->u.ext2_i.i_block_group;
for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
- tmp = get_group_desc (sb, i, &bh2);
- if ((le16_to_cpu(tmp->bg_used_dirs_count) << 8) <
- le16_to_cpu(tmp->bg_free_inodes_count)) {
+ tmp = ext2_get_group_desc (sb, i, &bh2);
+ if (tmp &&
+ (le16_to_cpu(tmp->bg_used_dirs_count) << 8) <
+ le16_to_cpu(tmp->bg_free_inodes_count)) {
gdp = tmp;
break;
}
@@ -329,9 +340,10 @@ repeat:
*/
if (!gdp) {
for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
- tmp = get_group_desc (sb, j, &bh2);
- if (le16_to_cpu(tmp->bg_free_inodes_count) &&
- le16_to_cpu(tmp->bg_free_inodes_count) >= avefreei) {
+ tmp = ext2_get_group_desc (sb, j, &bh2);
+ if (tmp &&
+ le16_to_cpu(tmp->bg_free_inodes_count) &&
+ le16_to_cpu(tmp->bg_free_inodes_count) >= avefreei) {
if (!gdp ||
(le16_to_cpu(tmp->bg_free_blocks_count) >
le16_to_cpu(gdp->bg_free_blocks_count))) {
@@ -348,8 +360,8 @@ repeat:
* Try to place the inode in its parent directory
*/
i = dir->u.ext2_i.i_block_group;
- tmp = get_group_desc (sb, i, &bh2);
- if (le16_to_cpu(tmp->bg_free_inodes_count))
+ tmp = ext2_get_group_desc (sb, i, &bh2);
+ if (tmp && le16_to_cpu(tmp->bg_free_inodes_count))
gdp = tmp;
else
{
@@ -361,8 +373,9 @@ repeat:
i += j;
if (i >= sb->u.ext2_sb.s_groups_count)
i -= sb->u.ext2_sb.s_groups_count;
- tmp = get_group_desc (sb, i, &bh2);
- if (le16_to_cpu(tmp->bg_free_inodes_count)) {
+ tmp = ext2_get_group_desc (sb, i, &bh2);
+ if (tmp &&
+ le16_to_cpu(tmp->bg_free_inodes_count)) {
gdp = tmp;
break;
}
@@ -376,8 +389,9 @@ repeat:
for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++) {
if (++i >= sb->u.ext2_sb.s_groups_count)
i = 0;
- tmp = get_group_desc (sb, i, &bh2);
- if (le16_to_cpu(tmp->bg_free_inodes_count)) {
+ tmp = ext2_get_group_desc (sb, i, &bh2);
+ if (tmp &&
+ le16_to_cpu(tmp->bg_free_inodes_count)) {
gdp = tmp;
break;
}
@@ -391,6 +405,13 @@ repeat:
return NULL;
}
bitmap_nr = load_inode_bitmap (sb, i);
+ if (bitmap_nr < 0) {
+ unlock_super (sb);
+ iput(inode);
+ *err = -EIO;
+ return NULL;
+ }
+
bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
if ((j = ext2_find_first_zero_bit ((unsigned long *) bh->b_data,
EXT2_INODES_PER_GROUP(sb))) <
@@ -504,9 +525,14 @@ unsigned long ext2_count_free_inodes (struct super_block * sb)
bitmap_count = 0;
gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
- gdp = get_group_desc (sb, i, NULL);
+ gdp = ext2_get_group_desc (sb, i, NULL);
+ if (!gdp)
+ continue;
desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
bitmap_nr = load_inode_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ continue;
+
x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
EXT2_INODES_PER_GROUP(sb) / 8);
printk ("group %d: stored = %d, counted = %lu\n",
@@ -536,9 +562,14 @@ void ext2_check_inodes_bitmap (struct super_block * sb)
bitmap_count = 0;
gdp = NULL;
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
- gdp = get_group_desc (sb, i, NULL);
+ gdp = ext2_get_group_desc (sb, i, NULL);
+ if (!gdp)
+ continue;
desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
bitmap_nr = load_inode_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ continue;
+
x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
EXT2_INODES_PER_GROUP(sb) / 8);
if (le16_to_cpu(gdp->bg_free_inodes_count) != x)
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index f752229ce..a48723031 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -12,9 +12,12 @@
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
- * Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
+ * Goal-directed block allocation by Stephen Tweedie
+ * (sct@dcs.ed.ac.uk), 1993, 1998
* Big-endian to little-endian byte-swapping/bitmaps by
* David S. Miller (davem@caip.rutgers.edu), 1995
+ * 64-bit file support on 64-bit platforms by Jakub Jelinek
+ * (jj@sunsite.ms.mff.cuni.cz)
*/
#include <asm/uaccess.h>
@@ -417,9 +420,44 @@ struct buffer_head * ext2_bread (struct inode * inode, int block,
int create, int *err)
{
struct buffer_head * bh;
-
+ int prev_blocks;
+
+ prev_blocks = inode->i_blocks;
+
bh = ext2_getblk (inode, block, create, err);
- if (!bh || buffer_uptodate(bh))
+ if (!bh)
+ return bh;
+
+ /*
+ * If the inode has grown, and this is a directory, then perform
+ * preallocation of a few more blocks to try to keep directory
+ * fragmentation down.
+ */
+ if (create &&
+ S_ISDIR(inode->i_mode) &&
+ inode->i_blocks > prev_blocks &&
+ EXT2_HAS_COMPAT_FEATURE(inode->i_sb,
+ EXT2_FEATURE_COMPAT_DIR_PREALLOC)) {
+ int i;
+ struct buffer_head *tmp_bh;
+
+ for (i = 1;
+ i < EXT2_SB(inode->i_sb)->s_es->s_prealloc_dir_blocks;
+ i++) {
+ /*
+ * ext2_getblk will zero out the contents of the
+ * directory for us
+ */
+ tmp_bh = ext2_getblk(inode, block+i, create, err);
+ if (!tmp_bh) {
+ brelse (bh);
+ return 0;
+ }
+ brelse (tmp_bh);
+ }
+ }
+
+ if (buffer_uptodate(bh))
return bh;
ll_rw_block (READ, 1, &bh);
wait_on_buffer (bh);
@@ -447,18 +485,23 @@ void ext2_read_inode (struct inode * inode)
inode->i_ino > le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_inodes_count)) {
ext2_error (inode->i_sb, "ext2_read_inode",
"bad inode number: %lu", inode->i_ino);
- return;
+ goto bad_inode;
}
block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb);
- if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count)
- ext2_panic (inode->i_sb, "ext2_read_inode",
+ if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count) {
+ ext2_error (inode->i_sb, "ext2_read_inode",
"group >= groups count");
+ goto bad_inode;
+ }
group_desc = block_group >> EXT2_DESC_PER_BLOCK_BITS(inode->i_sb);
desc = block_group & (EXT2_DESC_PER_BLOCK(inode->i_sb) - 1);
bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc];
- if (!bh)
- ext2_panic (inode->i_sb, "ext2_read_inode",
+ if (!bh) {
+ ext2_error (inode->i_sb, "ext2_read_inode",
"Descriptor not loaded");
+ goto bad_inode;
+ }
+
gdp = (struct ext2_group_desc *) bh->b_data;
/*
* Figure out the offset within the block group inode table
@@ -467,10 +510,12 @@ void ext2_read_inode (struct inode * inode)
EXT2_INODE_SIZE(inode->i_sb);
block = le32_to_cpu(gdp[desc].bg_inode_table) +
(offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb));
- if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize)))
- ext2_panic (inode->i_sb, "ext2_read_inode",
- "unable to read i-node block - "
+ if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) {
+ ext2_error (inode->i_sb, "ext2_read_inode",
+ "unable to read inode block - "
"inode=%lu, block=%lu", inode->i_ino, block);
+ goto bad_inode;
+ }
offset &= (EXT2_BLOCK_SIZE(inode->i_sb) - 1);
raw_inode = (struct ext2_inode *) (bh->b_data + offset);
@@ -493,7 +538,20 @@ void ext2_read_inode (struct inode * inode)
inode->u.ext2_i.i_frag_size = raw_inode->i_fsize;
inode->u.ext2_i.i_osync = 0;
inode->u.ext2_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
- inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
+ if (S_ISDIR(inode->i_mode))
+ inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
+ else {
+ inode->u.ext2_i.i_dir_acl = 0;
+ inode->u.ext2_i.i_high_size =
+ le32_to_cpu(raw_inode->i_size_high);
+#if BITS_PER_LONG < 64
+ if (raw_inode->i_size_high)
+ inode->i_size = (__u32)-1;
+#else
+ inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high))
+ << 32;
+#endif
+ }
inode->u.ext2_i.i_version = le32_to_cpu(raw_inode->i_version);
inode->u.ext2_i.i_block_group = block_group;
inode->u.ext2_i.i_next_alloc_block = 0;
@@ -542,6 +600,11 @@ void ext2_read_inode (struct inode * inode)
inode->i_attr_flags |= ATTR_FLAG_NOATIME;
inode->i_flags |= MS_NOATIME;
}
+ return;
+
+bad_inode:
+ make_bad_inode(inode);
+ return;
}
static int ext2_update_inode(struct inode * inode, int do_sync)
@@ -561,18 +624,22 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
inode->i_ino > le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_inodes_count)) {
ext2_error (inode->i_sb, "ext2_write_inode",
"bad inode number: %lu", inode->i_ino);
- return 0;
+ return -EIO;
}
block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb);
- if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count)
- ext2_panic (inode->i_sb, "ext2_write_inode",
+ if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count) {
+ ext2_error (inode->i_sb, "ext2_write_inode",
"group >= groups count");
+ return -EIO;
+ }
group_desc = block_group >> EXT2_DESC_PER_BLOCK_BITS(inode->i_sb);
desc = block_group & (EXT2_DESC_PER_BLOCK(inode->i_sb) - 1);
bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc];
- if (!bh)
- ext2_panic (inode->i_sb, "ext2_write_inode",
+ if (!bh) {
+ ext2_error (inode->i_sb, "ext2_write_inode",
"Descriptor not loaded");
+ return -EIO;
+ }
gdp = (struct ext2_group_desc *) bh->b_data;
/*
* Figure out the offset within the block group inode table
@@ -581,10 +648,12 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
EXT2_INODE_SIZE(inode->i_sb);
block = le32_to_cpu(gdp[desc].bg_inode_table) +
(offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb));
- if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize)))
- ext2_panic (inode->i_sb, "ext2_write_inode",
- "unable to read i-node block - "
+ if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) {
+ ext2_error (inode->i_sb, "ext2_write_inode",
+ "unable to read inode block - "
"inode=%lu, block=%lu", inode->i_ino, block);
+ return -EIO;
+ }
offset &= EXT2_BLOCK_SIZE(inode->i_sb) - 1;
raw_inode = (struct ext2_inode *) (bh->b_data + offset);
@@ -603,7 +672,16 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
raw_inode->i_frag = inode->u.ext2_i.i_frag_no;
raw_inode->i_fsize = inode->u.ext2_i.i_frag_size;
raw_inode->i_file_acl = cpu_to_le32(inode->u.ext2_i.i_file_acl);
- raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl);
+ if (S_ISDIR(inode->i_mode))
+ raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl);
+ else {
+#if BITS_PER_LONG < 64
+ raw_inode->i_size_high =
+ cpu_to_le32(inode->u.ext2_i.i_high_size);
+#else
+ raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32);
+#endif
+ }
raw_inode->i_version = cpu_to_le32(inode->u.ext2_i.i_version);
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
@@ -620,7 +698,7 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
printk ("IO error syncing ext2 inode ["
"%s:%08lx]\n",
kdevname(inode->i_dev), inode->i_ino);
- err = -1;
+ err = -EIO;
}
}
brelse (bh);
@@ -648,7 +726,7 @@ int ext2_notify_change(struct dentry *dentry, struct iattr *iattr)
(ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^
(inode->u.ext2_i.i_flags &
(EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
- if (securelevel > 0 || !fsuser())
+ if (!fsuser())
goto out;
} else if ((current->fsuid != inode->i_uid) && !fsuser())
goto out;
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index c0514c01e..70d4fc563 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -19,16 +19,18 @@
int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
unsigned long arg)
{
- unsigned long flags;
+ unsigned int flags;
ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg);
switch (cmd) {
case EXT2_IOC_GETFLAGS:
+ flags = inode->u.ext2_i.i_flags & EXT2_FL_USER_VISIBLE;
return put_user(inode->u.ext2_i.i_flags, (int *) arg);
case EXT2_IOC_SETFLAGS:
if (get_user(flags, (int *) arg))
- return -EFAULT;
+ return -EFAULT;
+ flags = flags & EXT2_FL_USER_MODIFIABLE;
/*
* The IMMUTABLE and APPEND_ONLY flags can only be changed by
* the super user when the security level is zero.
@@ -37,14 +39,15 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
(inode->u.ext2_i.i_flags &
(EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
/* This test looks nicer. Thanks to Pauline Middelink */
- if (!fsuser() || securelevel > 0)
+ if (!fsuser())
return -EPERM;
} else
if ((current->fsuid != inode->i_uid) && !fsuser())
return -EPERM;
if (IS_RDONLY(inode))
return -EROFS;
- inode->u.ext2_i.i_flags = flags;
+ inode->u.ext2_i.i_flags = (inode->u.ext2_i.i_flags &
+ ~EXT2_FL_USER_MODIFIABLE) | flags;
if (flags & EXT2_SYNC_FL)
inode->i_flags |= MS_SYNCHRONOUS;
else
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index f792f19f7..e043163dc 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -14,6 +14,8 @@
*
* Big-endian to little-endian byte-swapping/bitmaps by
* David S. Miller (davem@caip.rutgers.edu), 1995
+ * Directory entry file type support and forward compatibility hooks
+ * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
*/
#include <asm/uaccess.h>
@@ -39,18 +41,12 @@
/*
* NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure.
*/
-static int ext2_match (int len, const char * const name,
- struct ext2_dir_entry * de)
+static inline int ext2_match (int len, const char * const name,
+ struct ext2_dir_entry_2 * de)
{
if (!de || !le32_to_cpu(de->inode) || len > EXT2_NAME_LEN)
return 0;
- /*
- * "" means "." ---> so paths like "/usr/lib//libc.a" work
- */
- if (!len && le16_to_cpu(de->name_len) == 1 && (de->name[0] == '.') &&
- (de->name[1] == '\0'))
- return 1;
- if (len != le16_to_cpu(de->name_len))
+ if (len != de->name_len)
return 0;
return !memcmp(name, de->name, len);
}
@@ -65,7 +61,7 @@ static int ext2_match (int len, const char * const name,
*/
static struct buffer_head * ext2_find_entry (struct inode * dir,
const char * const name, int namelen,
- struct ext2_dir_entry ** res_dir)
+ struct ext2_dir_entry_2 ** res_dir)
{
struct super_block * sb;
struct buffer_head * bh_use[NAMEI_RA_SIZE];
@@ -96,7 +92,7 @@ static struct buffer_head * ext2_find_entry (struct inode * dir,
for (block = 0, offset = 0; offset < dir->i_size; block++) {
struct buffer_head * bh;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
char * dlimit;
if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {
@@ -105,9 +101,11 @@ static struct buffer_head * ext2_find_entry (struct inode * dir,
}
bh = bh_use[block % NAMEI_RA_SIZE];
if (!bh) {
+#if 0
ext2_error (sb, "ext2_find_entry",
"directory #%lu contains a hole at offset %lu",
dir->i_ino, offset);
+#endif
offset += sb->s_blocksize;
continue;
}
@@ -119,13 +117,13 @@ static struct buffer_head * ext2_find_entry (struct inode * dir,
break;
}
- de = (struct ext2_dir_entry *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) bh->b_data;
dlimit = bh->b_data + sb->s_blocksize;
while ((char *) de < dlimit) {
if (!ext2_check_dir_entry ("ext2_find_entry", dir,
de, bh, offset))
goto failure;
- if (le32_to_cpu(de->inode) != 0 && ext2_match (namelen, name, de)) {
+ if (ext2_match (namelen, name, de)) {
for (i = 0; i < NAMEI_RA_SIZE; ++i) {
if (bh_use[i] != bh)
brelse (bh_use[i]);
@@ -134,7 +132,7 @@ static struct buffer_head * ext2_find_entry (struct inode * dir,
return bh;
}
offset += le16_to_cpu(de->rec_len);
- de = (struct ext2_dir_entry *)
+ de = (struct ext2_dir_entry_2 *)
((char *) de + le16_to_cpu(de->rec_len));
}
@@ -158,7 +156,7 @@ failure:
int ext2_lookup(struct inode * dir, struct dentry *dentry)
{
struct inode * inode;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
struct buffer_head * bh;
if (dentry->d_name.len > EXT2_NAME_LEN)
@@ -190,13 +188,13 @@ int ext2_lookup(struct inode * dir, struct dentry *dentry)
*/
static struct buffer_head * ext2_add_entry (struct inode * dir,
const char * name, int namelen,
- struct ext2_dir_entry ** res_dir,
+ struct ext2_dir_entry_2 ** res_dir,
int *err)
{
unsigned long offset;
unsigned short rec_len;
struct buffer_head * bh;
- struct ext2_dir_entry * de, * de1;
+ struct ext2_dir_entry_2 * de, * de1;
struct super_block * sb;
*err = -EINVAL;
@@ -226,7 +224,7 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
return NULL;
rec_len = EXT2_DIR_REC_LEN(namelen);
offset = 0;
- de = (struct ext2_dir_entry *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) bh->b_data;
*err = -ENOSPC;
while (1) {
if ((char *)de >= sb->s_blocksize + bh->b_data) {
@@ -243,16 +241,17 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
ext2_debug ("creating next block\n");
- de = (struct ext2_dir_entry *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) bh->b_data;
de->inode = le32_to_cpu(0);
de->rec_len = le16_to_cpu(sb->s_blocksize);
dir->i_size = offset + sb->s_blocksize;
+ dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
} else {
ext2_debug ("skipping to next block\n");
- de = (struct ext2_dir_entry *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) bh->b_data;
}
}
if (!ext2_check_dir_entry ("ext2_add_entry", dir, de, bh,
@@ -261,24 +260,25 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
brelse (bh);
return NULL;
}
- if (le32_to_cpu(de->inode) != 0 && ext2_match (namelen, name, de)) {
+ if (ext2_match (namelen, name, de)) {
*err = -EEXIST;
brelse (bh);
return NULL;
}
if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) ||
- (le16_to_cpu(de->rec_len) >= EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len)) + rec_len)) {
+ (le16_to_cpu(de->rec_len) >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
offset += le16_to_cpu(de->rec_len);
if (le32_to_cpu(de->inode)) {
- de1 = (struct ext2_dir_entry *) ((char *) de +
- EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len)));
+ de1 = (struct ext2_dir_entry_2 *) ((char *) de +
+ EXT2_DIR_REC_LEN(de->name_len));
de1->rec_len = cpu_to_le16(le16_to_cpu(de->rec_len) -
- EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len)));
- de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len)));
+ EXT2_DIR_REC_LEN(de->name_len));
+ de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
de = de1;
}
de->inode = cpu_to_le32(0);
- de->name_len = cpu_to_le16(namelen);
+ de->name_len = namelen;
+ de->file_type = 0;
memcpy (de->name, name, namelen);
/*
* XXX shouldn't update any times until successful
@@ -292,6 +292,7 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
* and/or different from the directory change time.
*/
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
@@ -300,7 +301,7 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
return bh;
}
offset += le16_to_cpu(de->rec_len);
- de = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
+ de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
}
brelse (bh);
return NULL;
@@ -310,15 +311,15 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
* ext2_delete_entry deletes a directory entry by merging it with the
* previous entry
*/
-static int ext2_delete_entry (struct ext2_dir_entry * dir,
+static int ext2_delete_entry (struct ext2_dir_entry_2 * dir,
struct buffer_head * bh)
{
- struct ext2_dir_entry * de, * pde;
+ struct ext2_dir_entry_2 * de, * pde;
int i;
i = 0;
pde = NULL;
- de = (struct ext2_dir_entry *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) bh->b_data;
while (i < bh->b_size) {
if (!ext2_check_dir_entry ("ext2_delete_entry", NULL,
de, bh, i))
@@ -333,7 +334,7 @@ static int ext2_delete_entry (struct ext2_dir_entry * dir,
}
i += le16_to_cpu(de->rec_len);
pde = de;
- de = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
+ de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
}
return -ENOENT;
}
@@ -350,7 +351,7 @@ int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
{
struct inode * inode;
struct buffer_head * bh;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
int err = -EIO;
/*
@@ -371,6 +372,9 @@ int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
return err;
}
de->inode = cpu_to_le32(inode->i_ino);
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_REG_FILE;
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
@@ -386,7 +390,7 @@ int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
{
struct inode * inode;
struct buffer_head * bh;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
int err = -EIO;
err = -ENAMETOOLONG;
@@ -400,29 +404,48 @@ int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
inode->i_uid = current->fsuid;
inode->i_mode = mode;
inode->i_op = NULL;
- if (S_ISREG(inode->i_mode))
+ bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+ if (!bh)
+ goto out_no_entry;
+ de->inode = cpu_to_le32(inode->i_ino);
+ dir->i_version = ++event;
+ if (S_ISREG(inode->i_mode)) {
inode->i_op = &ext2_file_inode_operations;
- else if (S_ISDIR(inode->i_mode)) {
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_REG_FILE;
+ } else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ext2_dir_inode_operations;
if (dir->i_mode & S_ISGID)
inode->i_mode |= S_ISGID;
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_DIR;
}
- else if (S_ISLNK(inode->i_mode))
+ else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &ext2_symlink_inode_operations;
- else if (S_ISCHR(inode->i_mode))
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_SYMLINK;
+ } else if (S_ISCHR(inode->i_mode)) {
inode->i_op = &chrdev_inode_operations;
- else if (S_ISBLK(inode->i_mode))
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_CHRDEV;
+ } else if (S_ISBLK(inode->i_mode)) {
inode->i_op = &blkdev_inode_operations;
- else if (S_ISFIFO(inode->i_mode))
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_BLKDEV;
+ } else if (S_ISFIFO(inode->i_mode)) {
init_fifo(inode);
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_FIFO;
+ }
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = to_kdev_t(rdev);
mark_inode_dirty(inode);
- bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh)
- goto out_no_entry;
- de->inode = cpu_to_le32(inode->i_ino);
- dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
ll_rw_block (WRITE, 1, &bh);
@@ -445,7 +468,7 @@ int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
struct inode * inode;
struct buffer_head * bh, * dir_block;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
int err;
err = -ENAMETOOLONG;
@@ -463,6 +486,7 @@ int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
inode->i_op = &ext2_dir_inode_operations;
inode->i_size = inode->i_sb->s_blocksize;
+ inode->i_blocks = 0;
dir_block = ext2_bread (inode, 0, 1, &err);
if (!dir_block) {
inode->i_nlink--; /* is this nlink == 0? */
@@ -470,17 +494,22 @@ int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
iput (inode);
return err;
}
- inode->i_blocks = inode->i_sb->s_blocksize / 512;
- de = (struct ext2_dir_entry *) dir_block->b_data;
+ de = (struct ext2_dir_entry_2 *) dir_block->b_data;
de->inode = cpu_to_le32(inode->i_ino);
- de->name_len = cpu_to_le16(1);
- de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len)));
+ de->name_len = 1;
+ de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(de->name_len));
strcpy (de->name, ".");
- de = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_DIR;
+ de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
de->inode = cpu_to_le32(dir->i_ino);
de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1));
- de->name_len = cpu_to_le16(2);
+ de->name_len = 2;
strcpy (de->name, "..");
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_DIR;
inode->i_nlink = 2;
mark_buffer_dirty(dir_block, 1);
brelse (dir_block);
@@ -492,6 +521,9 @@ int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
if (!bh)
goto out_no_entry;
de->inode = cpu_to_le32(inode->i_ino);
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_DIR;
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
@@ -499,6 +531,7 @@ int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
wait_on_buffer (bh);
}
dir->i_nlink++;
+ dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
d_instantiate(dentry, inode);
brelse (bh);
@@ -520,7 +553,7 @@ static int empty_dir (struct inode * inode)
{
unsigned long offset;
struct buffer_head * bh;
- struct ext2_dir_entry * de, * de1;
+ struct ext2_dir_entry_2 * de, * de1;
struct super_block * sb;
int err;
@@ -532,29 +565,32 @@ static int empty_dir (struct inode * inode)
inode->i_ino);
return 1;
}
- de = (struct ext2_dir_entry *) bh->b_data;
- de1 = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
+ de = (struct ext2_dir_entry_2 *) bh->b_data;
+ de1 = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
if (le32_to_cpu(de->inode) != inode->i_ino || !le32_to_cpu(de1->inode) ||
strcmp (".", de->name) || strcmp ("..", de1->name)) {
ext2_warning (inode->i_sb, "empty_dir",
"bad directory (dir #%lu) - no `.' or `..'",
inode->i_ino);
+ brelse (bh);
return 1;
}
offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
- de = (struct ext2_dir_entry *) ((char *) de1 + le16_to_cpu(de1->rec_len));
+ de = (struct ext2_dir_entry_2 *) ((char *) de1 + le16_to_cpu(de1->rec_len));
while (offset < inode->i_size ) {
if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
brelse (bh);
bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, &err);
if (!bh) {
+#if 0
ext2_error (sb, "empty_dir",
"directory #%lu contains a hole at offset %lu",
inode->i_ino, offset);
+#endif
offset += sb->s_blocksize;
continue;
}
- de = (struct ext2_dir_entry *) bh->b_data;
+ de = (struct ext2_dir_entry_2 *) bh->b_data;
}
if (!ext2_check_dir_entry ("empty_dir", inode, de, bh,
offset)) {
@@ -566,7 +602,7 @@ static int empty_dir (struct inode * inode)
return 0;
}
offset += le16_to_cpu(de->rec_len);
- de = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
+ de = (struct ext2_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
}
brelse (bh);
return 1;
@@ -577,7 +613,7 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
int retval;
struct inode * inode;
struct buffer_head * bh;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
retval = -ENAMETOOLONG;
if (dentry->d_name.len > EXT2_NAME_LEN)
@@ -652,6 +688,7 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
mark_inode_dirty(inode);
dir->i_nlink--;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
d_delete(dentry);
@@ -666,7 +703,7 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry)
int retval;
struct inode * inode;
struct buffer_head * bh;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
retval = -ENAMETOOLONG;
if (dentry->d_name.len > EXT2_NAME_LEN)
@@ -711,6 +748,7 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry)
wait_on_buffer (bh);
}
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(dir);
inode->i_nlink--;
mark_inode_dirty(inode);
@@ -726,7 +764,7 @@ out:
int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
{
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
struct inode * inode;
struct buffer_head * bh = NULL, * name_block = NULL;
char * link;
@@ -774,6 +812,9 @@ int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symnam
if (!bh)
goto out_no_entry;
de->inode = cpu_to_le32(inode->i_ino);
+ if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = EXT2_FT_SYMLINK;
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
@@ -797,7 +838,7 @@ int ext2_link (struct dentry * old_dentry,
struct inode * dir, struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
- struct ext2_dir_entry * de;
+ struct ext2_dir_entry_2 * de;
struct buffer_head * bh;
int err;
@@ -815,6 +856,21 @@ int ext2_link (struct dentry * old_dentry,
return err;
de->inode = cpu_to_le32(inode->i_ino);
+ if (EXT2_HAS_INCOMPAT_FEATURE(inode->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE)) {
+ if (S_ISREG(inode->i_mode))
+ de->file_type = EXT2_FT_REG_FILE;
+ else if (S_ISDIR(inode->i_mode))
+ de->file_type = EXT2_FT_DIR;
+ else if (S_ISLNK(inode->i_mode))
+ de->file_type = EXT2_FT_SYMLINK;
+ else if (S_ISCHR(inode->i_mode))
+ de->file_type = EXT2_FT_CHRDEV;
+ else if (S_ISBLK(inode->i_mode))
+ de->file_type = EXT2_FT_BLKDEV;
+ else if (S_ISFIFO(inode->i_mode))
+ de->file_type = EXT2_FT_FIFO;
+ }
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
if (IS_SYNC(dir)) {
@@ -831,8 +887,8 @@ int ext2_link (struct dentry * old_dentry,
}
#define PARENT_INO(buffer) \
- ((struct ext2_dir_entry *) ((char *) buffer + \
- le16_to_cpu(((struct ext2_dir_entry *) buffer)->rec_len)))->inode
+ ((struct ext2_dir_entry_2 *) ((char *) buffer + \
+ le16_to_cpu(((struct ext2_dir_entry_2 *) buffer)->rec_len)))->inode
/*
* rename uses retrying to avoid race-conditions: at least they should be
@@ -850,7 +906,7 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
{
struct inode * old_inode, * new_inode;
struct buffer_head * old_bh, * new_bh, * dir_bh;
- struct ext2_dir_entry * old_de, * new_de;
+ struct ext2_dir_entry_2 * old_de, * new_de;
int retval;
old_bh = new_bh = dir_bh = NULL;
@@ -942,6 +998,10 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
* ok, that's it
*/
new_de->inode = le32_to_cpu(old_inode->i_ino);
+ if (EXT2_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
+ EXT2_FEATURE_INCOMPAT_FILETYPE))
+ new_de->file_type = old_de->file_type;
+
ext2_delete_entry (old_de, old_bh);
old_dir->i_version = ++event;
@@ -951,6 +1011,7 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
mark_inode_dirty(new_inode);
}
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+ old_dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(old_dir);
if (dir_bh) {
PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
@@ -962,6 +1023,7 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
mark_inode_dirty(new_inode);
} else {
new_dir->i_nlink++;
+ new_dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
mark_inode_dirty(new_dir);
}
}
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 1adc82185..fa84e498f 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -107,12 +107,10 @@ void ext2_put_super (struct super_block * sb)
int db_count;
int i;
- lock_super (sb);
if (!(sb->s_flags & MS_RDONLY)) {
sb->u.ext2_sb.s_es->s_state = le16_to_cpu(sb->u.ext2_sb.s_mount_state);
mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
}
- sb->s_dev = 0;
db_count = sb->u.ext2_sb.s_db_per_group;
for (i = 0; i < db_count; i++)
if (sb->u.ext2_sb.s_group_desc[i])
@@ -126,7 +124,7 @@ void ext2_put_super (struct super_block * sb)
if (sb->u.ext2_sb.s_block_bitmap[i])
brelse (sb->u.ext2_sb.s_block_bitmap[i]);
brelse (sb->u.ext2_sb.s_sbh);
- unlock_super (sb);
+
MOD_DEC_USE_COUNT;
return;
}
@@ -516,11 +514,11 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
goto failed_mount;
}
}
- sb->u.ext2_sb.s_feature_compat = es->s_feature_compat;
- sb->u.ext2_sb.s_feature_incompat = es->s_feature_incompat;
- sb->u.ext2_sb.s_feature_ro_compat = es->s_feature_ro_compat;
+ sb->u.ext2_sb.s_feature_compat = le32_to_cpu(es->s_feature_compat);
+ sb->u.ext2_sb.s_feature_incompat = le32_to_cpu(es->s_feature_incompat);
+ sb->u.ext2_sb.s_feature_ro_compat = le32_to_cpu(es->s_feature_ro_compat);
sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE <<
- (__s32) le32_to_cpu(es->s_log_frag_size);
+ le32_to_cpu(es->s_log_frag_size);
if (sb->u.ext2_sb.s_frag_size)
sb->u.ext2_sb.s_frags_per_block = sb->s_blocksize /
sb->u.ext2_sb.s_frag_size;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 184a4d19b..25194e9a3 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -72,7 +72,6 @@ void fat_delete_inode(struct inode *inode)
void fat_put_super(struct super_block *sb)
{
- lock_super(sb);
if (MSDOS_SB(sb)->cvf_format) {
dec_cvf_format_use_count_by_version(MSDOS_SB(sb)->cvf_format->cvf_version);
MSDOS_SB(sb)->cvf_format->unmount_cvf(sb);
@@ -99,8 +98,7 @@ void fat_put_super(struct super_block *sb)
kfree(MSDOS_SB(sb)->options.iocharset);
MSDOS_SB(sb)->options.iocharset = NULL;
}
- sb->s_dev = 0;
- unlock_super(sb);
+
MOD_DEC_USE_COUNT;
return;
}
diff --git a/fs/filesystems.c b/fs/filesystems.c
index f56b35c53..dd603e2a9 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -26,6 +26,7 @@
#include <linux/auto_fs.h>
#include <linux/ntfs_fs.h>
#include <linux/hfs_fs.h>
+#include <linux/devpts_fs.h>
#include <linux/efs_fs.h>
#include <linux/major.h>
#include <linux/smp.h>
@@ -144,6 +145,10 @@ __initfunc(static void do_sys_setup(void))
init_adfs_fs();
#endif
+#ifdef CONFIG_DEVPTS_FS
+ init_devpts_fs();
+#endif
+
#ifdef CONFIG_NLS
init_nls();
#endif
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 9e278d383..81a1c2562 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -122,8 +122,6 @@ static void hfs_put_super(struct super_block *sb)
{
struct hfs_mdb *mdb = HFS_SB(sb)->s_mdb;
- lock_super(sb);
-
if (!(sb->s_flags & MS_RDONLY)) {
hfs_mdb_commit(mdb, 0);
sb->s_dirt = 0;
@@ -135,12 +133,8 @@ static void hfs_put_super(struct super_block *sb)
/* restore default blocksize for the device */
set_blocksize(sb->s_dev, BLOCK_SIZE);
- /* invalidate the superblock */
- sb->s_dev = 0;
-
MOD_DEC_USE_COUNT;
- unlock_super(sb);
return;
}
diff --git a/fs/hpfs/hpfs_fs.c b/fs/hpfs/hpfs_fs.c
index 667492fcd..5cc01646b 100644
--- a/fs/hpfs/hpfs_fs.c
+++ b/fs/hpfs/hpfs_fs.c
@@ -731,9 +731,6 @@ static void hpfs_read_inode(struct inode *inode)
static void hpfs_put_super(struct super_block *s)
{
- lock_super(s);
- s->s_dev = 0;
- unlock_super(s);
MOD_DEC_USE_COUNT;
}
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 5e2802365..03900d80a 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -49,14 +49,12 @@ void isofs_put_super(struct super_block *sb)
sb->u.isofs_sb.s_nls_iocharset = NULL;
}
#endif
- lock_super(sb);
#ifdef LEAK_CHECK
printk("Outstanding mallocs:%d, outstanding buffers: %d\n",
check_malloc, check_bread);
#endif
- sb->s_dev = 0;
- unlock_super(sb);
+
MOD_DEC_USE_COUNT;
return;
}
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 05bf6706d..8934dc012 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -59,7 +59,6 @@ void minix_put_super(struct super_block *sb)
{
int i;
- lock_super(sb);
if (!(sb->s_flags & MS_RDONLY)) {
sb->u.minix_sb.s_ms->s_state = sb->u.minix_sb.s_mount_state;
mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
@@ -70,8 +69,7 @@ void minix_put_super(struct super_block *sb)
brelse(sb->u.minix_sb.s_zmap[i]);
brelse (sb->u.minix_sb.s_sbh);
kfree(sb->u.minix_sb.s_imap);
- sb->s_dev = 0;
- unlock_super(sb);
+
MOD_DEC_USE_COUNT;
return;
}
diff --git a/fs/namei.c b/fs/namei.c
index 519a8ceac..a6de99ead 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -454,7 +454,6 @@ struct dentry * __namei(const char *pathname, int follow_link)
char *name;
struct dentry *dentry;
- check_dcache_memory();
name = getname(pathname);
dentry = (struct dentry *) name;
if (!IS_ERR(name)) {
@@ -528,7 +527,6 @@ struct dentry * open_namei(const char * pathname, int flag, int mode)
struct inode *inode;
struct dentry *dentry;
- check_dcache_memory();
mode &= S_IALLUGO & ~current->fs->umask;
mode |= S_IFREG;
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index c872c2b84..99488fca1 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -407,8 +407,6 @@ static void ncp_put_super(struct super_block *sb)
{
struct ncp_server *server = NCP_SBP(sb);
- lock_super(sb);
-
ncp_lock_server(server);
ncp_disconnect(server);
ncp_unlock_server(server);
@@ -424,9 +422,6 @@ static void ncp_put_super(struct super_block *sb)
ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
- sb->s_dev = 0;
- unlock_super(sb);
-
MOD_DEC_USE_COUNT;
}
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
index 5de6767e4..34f51d23a 100644
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -147,6 +147,9 @@ ncp_negotiate_size_and_options(struct ncp_server *server,
int size, int options, int *ret_size, int *ret_options) {
int result;
+ /* there is minimum */
+ if (size < 512) size = 512;
+
ncp_init_request(server);
ncp_add_word(server, htons(size));
ncp_add_byte(server, options);
@@ -157,7 +160,10 @@ ncp_negotiate_size_and_options(struct ncp_server *server,
return result;
}
- *ret_size = min(ntohs(ncp_reply_word(server, 0)), size);
+ /* NCP over UDP returns 0 (!!!) */
+ result = ntohs(ncp_reply_word(server, 0));
+ if (result >= 512) size=min(result, size);
+ *ret_size = size;
*ret_options = ncp_reply_byte(server, 4);
ncp_unlock_server(server);
diff --git a/fs/ncpfs/ncpsign_kernel.c b/fs/ncpfs/ncpsign_kernel.c
index bae89c197..f945da657 100644
--- a/fs/ncpfs/ncpsign_kernel.c
+++ b/fs/ncpfs/ncpsign_kernel.c
@@ -25,24 +25,24 @@
#define PVAL(buf,pos) ((unsigned)BVAL(buf,pos))
#define BSET(buf,pos,val) (BVAL(buf,pos) = (val))
-static inline word
+static inline __u16
WVAL_LH(__u8 * buf, int pos)
{
return PVAL(buf, pos) | PVAL(buf, pos + 1) << 8;
}
-static inline dword
+static inline __u32
DVAL_LH(__u8 * buf, int pos)
{
return WVAL_LH(buf, pos) | WVAL_LH(buf, pos + 2) << 16;
}
static inline void
-WSET_LH(__u8 * buf, int pos, word val)
+WSET_LH(__u8 * buf, int pos, __u16 val)
{
BSET(buf, pos, val & 0xff);
BSET(buf, pos + 1, val >> 8);
}
static inline void
-DSET_LH(__u8 * buf, int pos, dword val)
+DSET_LH(__u8 * buf, int pos, __u32 val)
{
WSET_LH(buf, pos, val & 0xffff);
WSET_LH(buf, pos + 2, val >> 16);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 2de790e42..d56e4e7e6 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -126,10 +126,6 @@ nfs_put_super(struct super_block *sb)
struct nfs_server *server = &sb->u.nfs_sb.s_server;
struct rpc_clnt *rpc;
- /*
- * Lock the super block while we bring down the daemons.
- */
- lock_super(sb);
if ((rpc = server->client) != NULL)
rpc_shutdown_client(rpc);
@@ -142,8 +138,7 @@ nfs_put_super(struct super_block *sb)
nfs_invalidate_dircache_sb(sb);
kfree(server->hostname);
- sb->s_dev = 0;
- unlock_super(sb);
+
MOD_DEC_USE_COUNT;
}
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index f12cdfd6b..65d3f76a2 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -1,5 +1,5 @@
/*
- * $Id: nfsroot.c,v 1.43 1997/10/16 19:55:27 mj Exp $
+ * $Id: nfsroot.c,v 1.45 1998/03/07 10:44:46 mj Exp $
*
* Copyright (C) 1995, 1996 Gero Kuhlmann <gero@gkminix.han.de>
*
@@ -59,6 +59,8 @@
* host IP address (but host name defaults to IP
* address anyway).
* Martin Mares : Use root_server_addr appropriately during setup.
+ * Martin Mares : Rewrote parameter parsing, now hopefully giving
+ * correct overriding.
*/
#include <linux/types.h>
@@ -83,11 +85,9 @@
/* Default path we try to mount. "%s" gets replaced by our IP address */
#define NFS_ROOT "/tftpboot/%s"
-#define NFS_ROOT_NAME_LEN 256
/* Parameters passed from the kernel command line */
-static char nfs_root_name[NFS_ROOT_NAME_LEN] __initdata = "default";
-static int nfs_params_parsed = 0;
+static char nfs_root_name[256] __initdata = "";
/* Address of NFS server */
static __u32 servaddr __initdata = 0;
@@ -150,19 +150,15 @@ static struct nfs_bool_opts {
/*
- * Prepare the NFS data structure and parse any options. This tries to
- * set as many values in the nfs_data structure as known right now.
+ * Extract IP address from the parameter string if needed. Note that we
+ * need to have root_server_addr set _before_ IPConfig gets called as it
+ * can override it.
*/
-__initfunc(static int root_nfs_name(char *name))
+__initfunc(static void root_nfs_parse_addr(char *name))
{
- char buf[NFS_MAXPATHLEN];
- char *cp, *cq, *options, *val;
int octets = 0;
+ char *cp, *cq;
- if (nfs_params_parsed)
- return nfs_params_parsed;
-
- /* It is possible to override the server IP number here */
cp = cq = name;
while (octets < 4) {
while (*cp >= '0' && *cp <= '9')
@@ -179,45 +175,20 @@ __initfunc(static int root_nfs_name(char *name))
if (*cp == ':')
*cp++ = '\0';
root_server_addr = in_aton(name);
- name = cp;
+ strcpy(name, cp);
}
+}
- /* Clear the nfs_data structure and setup the server hostname */
- memset(&nfs_data, 0, sizeof(nfs_data));
-
- /* Set the name of the directory to mount */
- if (root_server_path[0] && !strcmp(name, "default"))
- strncpy(buf, root_server_path, NFS_MAXPATHLEN-1);
- else
- strncpy(buf, name, NFS_MAXPATHLEN-1);
- buf[NFS_MAXPATHLEN-1] = '\0';
- if ((options = strchr(buf, ',')))
- *options++ = '\0';
- if (!strcmp(buf, "default"))
- strcpy(buf, NFS_ROOT);
- cp = system_utsname.nodename;
- if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) {
- printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
- return -1;
- }
- sprintf(nfs_path, buf, cp);
- /* Set some default values */
- nfs_port = -1;
- nfs_data.version = NFS_MOUNT_VERSION;
- nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */
- nfs_data.rsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
- nfs_data.wsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
- nfs_data.bsize = 0;
- nfs_data.timeo = 7;
- nfs_data.retrans = 3;
- nfs_data.acregmin = 3;
- nfs_data.acregmax = 60;
- nfs_data.acdirmin = 30;
- nfs_data.acdirmax = 60;
+/*
+ * Parse option string.
+ */
+__initfunc(static void root_nfs_parse(char *name, char *buf))
+{
+ char *options, *val, *cp;
- /* Process any options */
- if (options) {
+ if ((options = strchr(name, ','))) {
+ *options++ = 0;
cp = strtok(options, ",");
while (cp) {
if ((val = strchr(cp, '='))) {
@@ -239,6 +210,50 @@ __initfunc(static int root_nfs_name(char *name))
cp = strtok(NULL, ",");
}
}
+ if (name[0] && strcmp(name, "default")) {
+ strncpy(buf, name, NFS_MAXPATHLEN-1);
+ buf[NFS_MAXPATHLEN-1] = 0;
+ }
+}
+
+
+/*
+ * Prepare the NFS data structure and parse all options.
+ */
+__initfunc(static int root_nfs_name(char *name))
+{
+ char buf[NFS_MAXPATHLEN];
+ char *cp;
+
+ /* Set some default values */
+ memset(&nfs_data, 0, sizeof(nfs_data));
+ nfs_port = -1;
+ nfs_data.version = NFS_MOUNT_VERSION;
+ nfs_data.flags = NFS_MOUNT_NONLM; /* No lockd in nfs root yet */
+ nfs_data.rsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
+ nfs_data.wsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
+ nfs_data.bsize = 0;
+ nfs_data.timeo = 7;
+ nfs_data.retrans = 3;
+ nfs_data.acregmin = 3;
+ nfs_data.acregmax = 60;
+ nfs_data.acdirmin = 30;
+ nfs_data.acdirmax = 60;
+ strcpy(buf, NFS_ROOT);
+
+ /* Process options received from the remote server */
+ root_nfs_parse(root_server_path, buf);
+
+ /* Override them by options set on kernel command-line */
+ root_nfs_parse(name, buf);
+
+ cp = system_utsname.nodename;
+ if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) {
+ printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
+ return -1;
+ }
+ sprintf(nfs_path, buf, cp);
+
return 1;
}
@@ -317,7 +332,7 @@ __initfunc(void nfs_root_setup(char *line, int *ints))
line[sizeof(nfs_root_name) - strlen(NFS_ROOT) - 1] = '\0';
sprintf(nfs_root_name, NFS_ROOT, line);
}
- nfs_params_parsed = root_nfs_name(nfs_root_name);
+ root_nfs_parse_addr(nfs_root_name);
}
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index d190b21e4..8a8fc563f 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -693,12 +693,9 @@ static void ntfs_put_super(struct super_block *sb)
ntfs_volume *vol;
ntfs_debug(DEBUG_OTHER, "ntfs_put_super\n");
- /* Ensure that nobody uses the super block anymore */
- lock_super(sb);
+
vol=NTFS_SB2VOL(sb);
- /* Tell the kernel that the super block is no more used */
- sb->s_dev = 0;
- unlock_super(sb);
+
ntfs_release_volume(vol);
if(vol->nls_map)
unload_nls(vol->nls_map);
diff --git a/fs/ntfs/types.h b/fs/ntfs/types.h
index 97bb273b6..eabcd8590 100644
--- a/fs/ntfs/types.h
+++ b/fs/ntfs/types.h
@@ -14,7 +14,7 @@
#include <linux/fs.h>
#endif
-#if defined(i386) || defined(__i386__)
+#if defined(i386) || defined(__i386__) || defined(__alpha__)
/* unsigned integral types */
#ifndef NTFS_INTEGRAL_TYPES
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index ab9948a62..04da4f412 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -50,7 +50,7 @@ struct inode_operations proc_fd_inode_operations = {
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL /* permission */
+ proc_permission /* permission */
};
/*
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 16ee84225..b2feaeef1 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -70,6 +70,13 @@ static void proc_put_inode(struct inode *inode)
static void proc_delete_inode(struct inode *inode)
{
struct proc_dir_entry *de = inode->u.generic_ip;
+
+#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
+ if ((inode->i_ino >= PROC_OPENPROM_FIRST) &&
+ (inode->i_ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM))
+ return;
+#endif
+
if (de) {
/*
* Call the fill_inode hook to release module counts.
@@ -80,20 +87,13 @@ static void proc_delete_inode(struct inode *inode)
}
}
-static void proc_put_super(struct super_block *sb)
-{
- lock_super(sb);
- sb->s_dev = 0;
- unlock_super(sb);
-}
-
static struct super_operations proc_sops = {
proc_read_inode,
proc_write_inode,
proc_put_inode,
proc_delete_inode, /* delete_inode(struct inode *) */
NULL,
- proc_put_super,
+ NULL,
NULL,
proc_statfs,
NULL
@@ -129,6 +129,108 @@ static int parse_options(char *options,uid_t *uid,gid_t *gid)
return 1;
}
+/*
+ * The standard rules, copied from fs/namei.c:permission().
+ */
+static int standard_permission(struct inode *inode, int mask)
+{
+ int mode = inode->i_mode;
+
+ if ((mask & S_IWOTH) && IS_RDONLY(inode) &&
+ (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
+ return -EROFS; /* Nobody gets write access to a read-only fs */
+ else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
+ 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 0;
+ return -EACCES;
+}
+
+/*
+ * Set up permission rules for processes looking at other processes.
+ * You're not allowed to see a process unless it has the same or more
+ * restricted root than your own. This prevents a chrooted processes
+ * from escaping through the /proc entries of less restricted
+ * processes, and thus allows /proc to be safely mounted in a chrooted
+ * area.
+ *
+ * Note that root (uid 0) doesn't get permission for this either,
+ * since chroot is stronger than root.
+ *
+ * XXX TODO: use the dentry mechanism to make off-limits procs simply
+ * invisible rather than denied? Does each namespace root get its own
+ * dentry tree?
+ *
+ * This also applies the default permissions checks, as it only adds
+ * restrictions.
+ *
+ * Jeremy Fitzhardinge <jeremy@zip.com.au>
+ */
+int proc_permission(struct inode *inode, int mask)
+{
+ struct task_struct *p;
+ unsigned long ino = inode->i_ino;
+ unsigned long pid;
+ struct dentry *de, *base;
+
+ if (standard_permission(inode, mask) != 0)
+ return -EACCES;
+
+ /*
+ * Find the root of the processes being examined (if any).
+ * XXX Surely there's a better way of doing this?
+ */
+ if (ino >= PROC_OPENPROM_FIRST &&
+ ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM)
+ return 0; /* already allowed */
+
+ pid = ino >> 16;
+ if (pid == 0)
+ return 0; /* already allowed */
+
+ de = NULL;
+ base = current->fs->root;
+
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+
+ if (p && p->fs)
+ de = p->fs->root;
+ read_unlock(&tasklist_lock); /* FIXME! */
+
+ if (p == NULL)
+ return -EACCES; /* ENOENT? */
+
+ if (de == NULL)
+ {
+ /* kswapd and bdflush don't have proper root or cwd... */
+ return -EACCES;
+ }
+
+ /* XXX locking? */
+ for(;;)
+ {
+ struct dentry *parent;
+
+ if (de == base)
+ return 0; /* already allowed */
+
+ de = de->d_covers;
+ parent = de->d_parent;
+
+ if (de == parent)
+ break;
+
+ de = parent;
+ }
+
+ return -EACCES; /* incompatible roots */
+}
+
struct inode * proc_get_inode(struct super_block * sb, int ino,
struct proc_dir_entry * de)
{
diff --git a/fs/proc/link.c b/fs/proc/link.c
index 2f4abc945..28bb81a93 100644
--- a/fs/proc/link.c
+++ b/fs/proc/link.c
@@ -20,12 +20,6 @@ static int proc_readlink(struct dentry *, char *, int);
static struct dentry * proc_follow_link(struct dentry *, struct dentry *);
/*
- * PLAN9_SEMANTICS won't work any more: it used an ugly hack that broke
- * when the files[] array was updated only after the open code
- */
-#undef PLAN9_SEMANTICS
-
-/*
* links can't do much...
*/
static struct file_operations proc_fd_link_operations = {
@@ -58,7 +52,7 @@ struct inode_operations proc_link_inode_operations = {
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL /* permission */
+ proc_permission /* permission */
};
static struct dentry * proc_follow_link(struct dentry *dentry,
diff --git a/fs/proc/mem.c b/fs/proc/mem.c
index 1cbdbad9a..6478dab77 100644
--- a/fs/proc/mem.c
+++ b/fs/proc/mem.c
@@ -9,6 +9,7 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/proc_fs.h>
#include <asm/page.h>
#include <asm/uaccess.h>
@@ -336,5 +337,5 @@ struct inode_operations proc_mem_inode_operations = {
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL /* permission */
+ proc_permission /* permission */
};
diff --git a/fs/proc/openpromfs.c b/fs/proc/openpromfs.c
index aaf53006f..0380e1899 100644
--- a/fs/proc/openpromfs.c
+++ b/fs/proc/openpromfs.c
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.21 1997/08/19 02:05:48 davem Exp $
+/* $Id: openpromfs.c,v 1.26 1998/01/28 09:55:32 ecd Exp $
* openpromfs.c: /proc/openprom handling routines
*
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -55,13 +55,14 @@ static struct openpromfs_dev **devices;
#define NODEP2INO(no) (no + PROC_OPENPROM_FIRST + last_node)
static int openpromfs_create (struct inode *, struct dentry *, int);
-static int openpromfs_readdir(struct inode *, struct file *, void *, filldir_t);
+static int openpromfs_readdir(struct file *, void *, filldir_t);
static int openpromfs_lookup(struct inode *, struct dentry *dentry);
static int openpromfs_unlink (struct inode *, struct dentry *dentry);
-static long nodenum_read(struct inode *inode, struct file *file,
- char *buf, unsigned long count)
+static ssize_t nodenum_read(struct file *file, char *buf,
+ size_t count, loff_t *ppos)
{
+ struct inode *inode = file->f_dentry->d_inode;
char buffer[10];
if (count < 0 || !inode->u.generic_ip)
@@ -76,9 +77,10 @@ static long nodenum_read(struct inode *inode, struct file *file,
return count;
}
-static long property_read(struct inode *inode, struct file *filp,
- char *buf, unsigned long count)
+static ssize_t property_read(struct file *filp, char *buf,
+ size_t count, loff_t *ppos)
{
+ struct inode *inode = filp->f_dentry->d_inode;
int i, j, k;
u32 node;
char *p;
@@ -212,8 +214,8 @@ static long property_read(struct inode *inode, struct file *filp,
return count;
}
-static long property_write(struct inode *inode, struct file *filp,
- const char *buf, unsigned long count)
+static ssize_t property_write(struct file *filp, const char *buf,
+ size_t count, loff_t *ppos)
{
int i, j, k;
char *p;
@@ -224,7 +226,7 @@ static long property_write(struct inode *inode, struct file *filp,
if (filp->f_pos >= 0xffffff)
return -EINVAL;
if (!filp->private_data) {
- i = property_read (inode, filp, NULL, 0);
+ i = property_read (filp, NULL, 0, 0);
if (i)
return i;
}
@@ -741,9 +743,9 @@ static int openpromfs_lookup(struct inode * dir, struct dentry *dentry)
return 0;
}
-static int openpromfs_readdir(struct inode * inode, struct file * filp,
- void * dirent, filldir_t filldir)
+static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
+ struct inode *inode = filp->f_dentry->d_inode;
unsigned int ino;
u32 n;
int i, j;
@@ -1044,10 +1046,6 @@ EXPORT_NO_SYMBOLS;
int init_module (void)
#endif
{
-#ifndef __sparc_v9__
- if (!romvec->pv_romvers)
- return RET(ENODEV);
-#endif
nodes = (openpromfs_node *)__get_free_pages(GFP_KERNEL, 0);
if (!nodes) {
printk (KERN_WARNING "/proc/openprom: can't get free page\n");
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
index 6fdccf974..c53a440fe 100644
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -41,8 +41,8 @@ static int property_read_proc(char *page, char **start, off_t off,
* and "@10" to it.
*/
-static int devtree_readlink(struct inode *, char *, int);
-static struct dentry *devtree_follow_link(struct inode *, struct dentry *);
+static int devtree_readlink(struct dentry *, char *, int);
+static struct dentry *devtree_follow_link(struct dentry *, struct dentry *);
struct inode_operations devtree_symlink_inode_operations = {
NULL, /* no file-operations */
@@ -68,21 +68,23 @@ struct inode_operations devtree_symlink_inode_operations = {
static struct dentry *devtree_follow_link(struct dentry *dentry,
struct dentry *base)
{
+ struct inode *inode = dentry->d_inode;
struct proc_dir_entry * de;
char *link;
- de = (struct proc_dir_entry *) dentry->inode->u.generic_ip;
+ de = (struct proc_dir_entry *) inode->u.generic_ip;
link = (char *) de->data;
return lookup_dentry(link, base, 1);
}
static int devtree_readlink(struct dentry *dentry, char *buffer, int buflen)
{
+ struct inode *inode = dentry->d_inode;
struct proc_dir_entry * de;
char *link;
int linklen;
- de = (struct proc_dir_entry *) dentry->inode->u.generic_ip;
+ de = (struct proc_dir_entry *) inode->u.generic_ip;
link = (char *) de->data;
linklen = strlen(link);
if (linklen > buflen)
@@ -206,7 +208,8 @@ static void add_node(struct device_node *np, struct proc_dir_entry *de)
void proc_device_tree_init(void)
{
struct device_node *root;
-
+ if ( !have_of )
+ return;
proc_device_tree = create_proc_entry("device-tree", S_IFDIR, 0);
if (proc_device_tree == 0)
return;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index ad3a541cb..6225b3fd9 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -177,14 +177,14 @@ struct proc_dir_entry proc_sys_root = {
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
-static int (*proc_openprom_defreaddir_ptr)(struct inode *, struct file *, void *, filldir_t);
+static int (*proc_openprom_defreaddir_ptr)(struct file *, void *, filldir_t);
static int (*proc_openprom_deflookup_ptr)(struct inode *, struct dentry *);
void (*proc_openprom_use)(struct inode *, int) = 0;
static struct openpromfs_dev *proc_openprom_devices = NULL;
static ino_t proc_openpromdev_ino = PROC_OPENPROMD_FIRST;
struct inode_operations *
-proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, filldir_t),
+proc_openprom_register(int (*readdir)(struct file *, void *, filldir_t),
int (*lookup)(struct inode *, struct dentry *),
void (*use)(struct inode *, int),
struct openpromfs_dev ***devices)
@@ -236,14 +236,13 @@ proc_openprom_deregister(void)
#if defined(CONFIG_SUN_OPENPROMFS_MODULE) && defined(CONFIG_KMOD)
static int
-proc_openprom_defreaddir(struct inode * inode, struct file * filp,
- void * dirent, filldir_t filldir)
+proc_openprom_defreaddir(struct file * filp, void * dirent, filldir_t filldir)
{
request_module("openpromfs");
if ((proc_openprom_inode_operations.default_file_ops)->readdir !=
proc_openprom_defreaddir)
return (proc_openprom_inode_operations.default_file_ops)->readdir
- (inode, filp, dirent, filldir);
+ (filp, dirent, filldir);
return -EINVAL;
}
#define OPENPROM_DEFREADDIR proc_openprom_defreaddir
@@ -499,13 +498,6 @@ static struct proc_dir_entry proc_root_version = {
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_array_inode_operations
};
-#ifdef CONFIG_PCI_OLD_PROC
-static struct proc_dir_entry proc_root_pci = {
- PROC_PCI, 3, "pci",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
#ifdef CONFIG_ZORRO
static struct proc_dir_entry proc_root_zorro = {
PROC_ZORRO, 5, "zorro",
@@ -640,9 +632,6 @@ void proc_root_init(void)
proc_register(&proc_root, &proc_root_meminfo);
proc_register(&proc_root, &proc_root_kmsg);
proc_register(&proc_root, &proc_root_version);
-#ifdef CONFIG_PCI_OLD_PROC
- proc_register(&proc_root, &proc_root_pci);
-#endif
#ifdef CONFIG_ZORRO
proc_register(&proc_root, &proc_root_zorro);
#endif
@@ -707,9 +696,6 @@ void proc_root_init(void)
#endif
proc_bus = create_proc_entry("bus", S_IFDIR, 0);
-#ifdef CONFIG_PCI
- proc_bus_pci_init();
-#endif
}
/*
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index bc3a116b4..0e17b3e1d 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -157,9 +157,6 @@ outnobh:
static void
romfs_put_super(struct super_block *sb)
{
- lock_super(sb);
- sb->s_dev = 0;
- unlock_super(sb);
MOD_DEC_USE_COUNT;
return;
}
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 0264ceeb2..e850b7f82 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -322,8 +322,6 @@ smb_put_super(struct super_block *sb)
{
struct smb_sb_info *server = &(sb->u.smbfs_sb);
- lock_super(sb);
-
if (server->sock_file) {
smb_proc_disconnect(server);
smb_dont_catch_keepalive(server);
@@ -337,9 +335,6 @@ smb_put_super(struct super_block *sb)
kfree(sb->u.smbfs_sb.temp_buf);
if (server->packet)
smb_vfree(server->packet);
- sb->s_dev = 0;
-
- unlock_super(sb);
MOD_DEC_USE_COUNT;
}
diff --git a/fs/super.c b/fs/super.c
index 50a6cb9a6..0433dd251 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -668,18 +668,26 @@ static int do_umount(kdev_t dev, int unmount_root)
if (retval)
goto out;
- /* Forget any inodes */
- if (invalidate_inodes(sb)) {
- printk("VFS: Busy inodes after unmount. "
- "Self-destruct in 5 seconds. Bye-bye..\n");
- }
-
if (sb->s_op) {
if (sb->s_op->write_super && sb->s_dirt)
sb->s_op->write_super(sb);
+ }
+
+ lock_super(sb);
+ if (sb->s_op) {
if (sb->s_op->put_super)
sb->s_op->put_super(sb);
}
+
+ /* Forget any remaining inodes */
+ if (invalidate_inodes(sb)) {
+ printk("VFS: Busy inodes after unmount. "
+ "Self-destruct in 5 seconds. Have a nice day...\n");
+ }
+
+ sb->s_dev = 0; /* Free the superblock */
+ unlock_super(sb);
+
remove_vfsmnt(dev);
out:
return retval;
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 25dbe55df..583b94c25 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -492,12 +492,14 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
sb->s_op = &sysv_sops;
root_inode = iget(sb,SYSV_ROOT_INO);
sb->s_root = d_alloc_root(root_inode, NULL);
- unlock_super(sb);
if (!sb->s_root) {
printk("SysV FS: get root inode failed\n");
sysv_put_super(sb);
+ sb->s_dev = 0;
+ unlock_super(sb);
return NULL;
}
+ unlock_super(sb);
sb->s_dirt = 1;
/* brelse(bh); resp. brelse(bh1); brelse(bh2);
occurs when the disk is unmounted. */
@@ -530,15 +532,14 @@ void sysv_write_super (struct super_block *sb)
void sysv_put_super(struct super_block *sb)
{
- /* we can assume sysv_write_super() has already been called */
- lock_super(sb);
+ /* we can assume sysv_write_super() has already been called, and
+ and that the superblock is locked */
brelse(sb->sv_bh1);
if (sb->sv_bh1 != sb->sv_bh2) brelse(sb->sv_bh2);
/* switch back to default block size */
if (sb->s_blocksize != BLOCK_SIZE)
set_blocksize(sb->s_dev,BLOCK_SIZE);
- sb->s_dev = 0;
- unlock_super(sb);
+
MOD_DEC_USE_COUNT;
}
diff --git a/fs/ufs/ufs_super.c b/fs/ufs/ufs_super.c
index 6a378fb13..7fdac8dd6 100644
--- a/fs/ufs/ufs_super.c
+++ b/fs/ufs/ufs_super.c
@@ -335,15 +335,13 @@ void ufs_put_super (struct super_block * sb)
printk("ufs_put_super\n"); /* XXX */
}
- lock_super (sb);
+
/* XXX - sync fs data, set state to ok, and flush buffers */
set_blocksize (sb->s_dev, BLOCK_SIZE);
- sb->s_dev = 0;
/* XXX - free allocated kernel memory */
/* includes freeing usb page */
- unlock_super (sb);
MOD_DEC_USE_COUNT;
return;
diff --git a/fs/umsdos/README-WIP.txt b/fs/umsdos/README-WIP.txt
index ddc2911fc..1357fdd69 100644
--- a/fs/umsdos/README-WIP.txt
+++ b/fs/umsdos/README-WIP.txt
@@ -8,7 +8,7 @@ UMSDOS FILESYSTEM, AND MAYBE EVEN OTHER FILESYSTEMS IN USE.
YOU'VE BEEN WARNED.
--------- WARNING --------- WARNING --------- WARNING -----------
-Current status (980220) - UMSDOS dentry-WIP-Beta 0.82-1:
+Current status (980220) - UMSDOS dentry-WIP-Beta 0.82-3:
(1) pure MSDOS (no --linux-.--- EMD file):
@@ -19,7 +19,7 @@ Current status (980220) - UMSDOS dentry-WIP-Beta 0.82-1:
- creat file - works
- write file - works
- mkdir - works
-- rmdir - questionable. probable problem on non-empty dirs.
+- rmdir - QUESTIONABLE. probable problem on non-empty dirs.
Notes: possible very minor problems with dentry/inode/... kernel structures (very rare)
@@ -42,28 +42,29 @@ Notes: possible very minor problems with dentry/inode/... kernel structures (ver
- other ioctls - MOSTLY UNTESTED
- dangling symlink - UNTESTED !
-- create symlink - works on short names, but fails (gets
- truncated on long ones) (also
- due to some dentries problems, it may not
- be visible right away always - eg. before
- umount/mount)
+- create symlink - seems to work both on short & long names now !
- create hardlink - WARNING: NOT FIXED YET!
-- create file - creates short names, but probs with long ones ?
-- create special file - seems to work on short names.
-- write to file - seems to work on short names.
+- create file - seems to work both on short & long names now !
+- create special file - seems to work both on short & long names now !
+- write to file - seems to work both on short & long names now !
- rename file (same dir) - WARNING: NOT FIXED YET!
- rename file (dif. dir) - WARNING: NOT FIXED YET!
- rename dir (same dir) - WARNING: NOT FIXED YET!
- rename dir (dif. dir) - WARNING: NOT FIXED YET!
-- delete file - WARNING: NOT FIXED YET!
+- delete file - seems to work fully now!
- notify_change (chown,perms) - seems to work!
- delete hardlink - WARNING: NOT FIXED YET!
-- mkdir - seems to work, even with long names ! (but
- due to some dentries problems, it may not
- be visible right away always - eg. before
- umount/mount)
+- mkdir - seems to work both on short & long names now !
- rmdir - WARNING: NOT FIXED YET!
-- umssyncing - does something :-), but NEEDS EXTENSIVE TESTING
+- umssyncing - seems to work, but NEEDS EXTENSIVE TESTING
+
+- CVF-FAT stuff (compressed DOS filesystem) - there is some support from
+ Frank Gockel <gockel@sent13.uni-duisburg.de> to use it even under
+ umsdosfs. But I have no way of testing it -- please let me know if there
+ are problems that are specific to umsdos (eg. it works under msdosfs, but
+ not under umsdosfs)
+
+
Notes: moderate dentry/inode kernel structures trashing. Probably some other
kernel structures compromised. Have SysRq support compiled in, and use
@@ -77,16 +78,18 @@ Notes3: Notes2 is probably somewhat outdated now that hardlink/symlink stuff
is supposed to be fixed enough to work, but I haven't got the time to test
it.
-Note4: on failure of creating of long filenames: MSDOS filename gets
-created, and EMD entry gets created. Check: either they mismatch, or EMD
-entry contains some wrong flags.
+Note5: rmdir(2) fails with EBUSY - sdir->i_count > 1 (like 7 ??). It must be
+some error with dir->i_count++, or something related to iput() ? See if
+number changes if we access the dir in different ways..
-Note5: rmdir(2) probably fails because do_rmdir calls lock_parent, which
-uses dentry->d_parent, which we neglect to set, so it returns -ENOENT.
-Probably same problem on unlink(2) ? What to do ? How to set
-dentry->d_parent to something useful ?? Must I recurse down whole pathname
-and set one by one all directory components ?! or only last one is really
-needed ? help !
+Note6: there is problem with unmounting umsdosfs, it seems to stay
+registered or something. Remounting same device on any mount point with
+different fstype (like msdos or vfat) ignores fstype and umsdosfs kicks back
+in.
+
+Note7: also we screwed umount(2)-ing the fs at times (EBUSY), by removing
+all those iput/dput's. When rest of code is fixed, we'll put them back at
+(hopefully) correct places.
------------------------------------------------------------------------------
@@ -110,10 +113,10 @@ should we destroy temp dentries ? using d_invalidate ? using d_drop ? just
dput them ?
I'm unfortunatelly somewhat out of time to read linux-kernel, but I do check
-for any messages having UMSDOS in subject, and read them. I should reply to
-any direct Email in few days. If I don't - probably I never got your
-message. You can try mnalis@open.hr or mnalis@voyager.hr; however
-mnalis@jagor.srce.hr is preferable one.
+for any messages having UMSDOS in subject, and read them. I might miss it in
+all that volume, though. I should reply to any direct Email in few days. If
+I don't - probably I never got your message. You can try mnalis@open.hr or
+mnalis@voyager.hr; however mnalis@jagor.srce.hr is preferable one.
------------------------------------------------------------------------------
@@ -122,7 +125,7 @@ some of my notes for myself /mn/:
+ hardlinks/symlinks. test with files in not_the_same_dir
- also test not_the_same_dir for other file operations like rename etc.
- iput: device 00:00 inode 318 still has aliases! problem. Check in iput()
- for device 0,0. Probably null pointer passed arount when it shouldn't be ?
+ for device 0,0. Probably null pointer passed around when it shouldn't be ?
- dput/iput problem...
- what about .dotfiles ? working ? multiple dots ? etc....
- fix stuff like dir->i_count++ to atomic_inc(&dir->i_count) and simular?
@@ -133,11 +136,23 @@ some of my notes for myself /mn/:
- when should dput()/iput() be used ?!!
-- probably problem with filename mangling somewhere, since both create and
- write to file work on short filenames, but fail on long ones. Path
- components may be of any size (eg. mkfifo /mnt/Very_long_dir2/blah1 will
- succeed, but mkfifo /mnt/very_long_filename.txt won't)
-
-
- what is dir->i_count++ ? locking directory ? should this be lock_parent or
something ?
+
+- i_binary=2 is for CVF (compressed filesystem).
+
+- SECURITY WARNING: short dentries should be invalidated, or they could be
+ accessed instead of proper long names.
+
+- as for iput() : (my only pointer so far. anyone else ?)
+
+>development I only know about iput. All functions that get an inode as
+>argument and don't return it have to call iput on it before exit, i.e. when
+>it is no longer needed and the code returns to vfs layer. The rest is quite
+>new to me, but it might be similar for dput. Typical side effect of a
+>missing iput was a memory runout (but no crash). You also couldn't unmount
+>the filesystem later though no process was using it. On the other hand, one
+>iput too much lead to serious pointer corruption and crashed the system
+>very soon. I used to look at the FAT filesystem and copy those pieces of
+>
+> Frank
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index 52a72367e..288c77d45 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -36,7 +36,7 @@ int compat_umsdos_real_lookup (struct inode *dir,const char *name,int len, struc
int rv;
struct dentry *dentry;
- dentry = creat_dentry (name, len, NULL);
+ dentry = creat_dentry (name, len, NULL, NULL);
rv = umsdos_real_lookup(dir,dentry);
if (inode) *inode = dentry->d_inode;
kill_dentry (dentry);
@@ -50,7 +50,7 @@ int compat_msdos_create(struct inode *dir,const char *name,int len, int mode, st
int rv;
struct dentry *dentry;
- dentry = creat_dentry (name, len, NULL);
+ dentry = creat_dentry (name, len, NULL, NULL);
rv = msdos_create(dir,dentry,mode);
if(inode != NULL) *inode = dentry->d_inode;
@@ -270,10 +270,10 @@ static int umsdos_readdir_x(
}
Printk (("Trouve ino %ld ",inode->i_ino));
if (u_entry != NULL) *u_entry = entry;
- iput (inode);
+ /* iput (inode); FIXME */
break;
}
- iput (inode);
+ /* iput (inode); FIXME */
}else{
/* #Specification: umsdos / readdir / not in MSDOS
During a readdir operation, if the file is not
@@ -295,7 +295,7 @@ static int umsdos_readdir_x(
the special offset.
*/
if (filp->f_pos == 0) filp->f_pos = start_fpos;
- iput(emd_dir);
+ /* iput(emd_dir); FIXME */
}
}
umsdos_endlookup(dir);
@@ -530,7 +530,7 @@ int umsdos_inode2entry (
ret = 0;
}else{
struct inode *emddir = umsdos_emd_dir_lookup(dir,0);
- iput (emddir);
+ /* iput (emddir); FIXME */
if (emddir == NULL){
/* This is a DOS directory */
struct UMSDOS_DIR_SEARCH bufk;
@@ -639,7 +639,7 @@ int umsdos_locate_path (
while (dir != root_inode){
struct inode *adir;
ret = umsdos_locate_ancestor (dir,&adir,&entry);
- iput (dir);
+ /* iput (dir); FIXME */
dir = NULL;
Printk (("ancestor %d ",ret));
if (ret == 0){
@@ -657,7 +657,7 @@ int umsdos_locate_path (
kfree (bpath);
}
Printk (("\n"));
- iput (dir);
+ /* iput (dir); FIXME */
return ret;
}
@@ -697,12 +697,16 @@ int umsdos_lookup_x (
struct inode *pseudo_root_inode=NULL;
int len = dentry->d_name.len;
const char *name = dentry->d_name.name;
+
+ Printk ((KERN_DEBUG "umsdos_lookup_x: /mn/ name=%.*s, dir=%lu, d_parent=%p\n", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino, dentry->d_parent)); /* FIXME /mn/ debug only */
+ if (dentry->d_parent) Printk ((KERN_DEBUG " d_parent is %.*s\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name)); /* FIXME : delme /mn/ */
+
root_inode = iget(dir->i_sb,UMSDOS_ROOT_INO);
/* pseudo_root_inode = iget( ... ) ? */
dentry->d_inode = NULL;
- umsdos_startlookup(dir);
+ umsdos_startlookup(dir);
if (len == 1 && name[0] == '.'){
- dentry->d_inode = dir;
+ d_add (dentry, dir);
dir->i_count++;
ret = 0;
}else if (len == 2 && name[0] == '.' && name[1] == '.'){
@@ -713,7 +717,7 @@ int umsdos_lookup_x (
pseudo root is returned.
*/
ret = 0;
- dentry->d_inode = pseudo_root;
+ d_add (dentry, pseudo_root);
pseudo_root->i_count++;
}else{
/* #Specification: locating .. / strategy
@@ -735,7 +739,7 @@ int umsdos_lookup_x (
struct inode *aadir;
struct umsdos_dirent entry;
ret = umsdos_locate_ancestor (dentry->d_inode,&aadir,&entry);
- iput (aadir);
+ /* iput (aadir); FIXME */
}
}
}else if (umsdos_is_pseudodos(dir,dentry)){
@@ -743,7 +747,7 @@ int umsdos_lookup_x (
A lookup of DOS in the pseudo root will always succeed
and return the inode of the real root.
*/
- dentry->d_inode = root_inode;
+ d_add (dentry, root_inode);
(dentry->d_inode)->i_count++;
ret = 0;
}else{
@@ -776,7 +780,7 @@ int umsdos_lookup_x (
Printk ((KERN_DEBUG "umsdos_lookup_x /mn/ debug: ino=%li\n", inode->i_ino));
/* we've found it. now get inode and put it in dentry. Is this ok /mn/ ? */
- dentry->d_inode = iget(dir->i_sb, inode->i_ino);
+ d_add (dentry, iget(dir->i_sb, inode->i_ino));
umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
Printk (("lookup ino %ld flags %d\n",inode->i_ino
@@ -796,7 +800,7 @@ int umsdos_lookup_x (
mode.
*/
Printk ((KERN_ERR "umsdos_lookup_x: warning: untested /mn/ Pseudo_root thingy\n"));
- iput (pseudo_root);
+ /* iput (pseudo_root); FIXME */
dentry->d_inode = NULL;
ret = -ENOENT;
}
@@ -804,7 +808,7 @@ int umsdos_lookup_x (
}
}
umsdos_endlookup(dir);
- iput (dir);
+ /* iput (dir); FIXME */
Printk ((KERN_DEBUG "umsdos_lookup_x: returning %d\n", ret));
return ret;
}
@@ -858,7 +862,7 @@ int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
*result = NULL;
if (path == NULL){
ret = -ENOMEM;
- iput (hlink);
+ /* iput (hlink); FIXME */
}else{
struct file filp;
loff_t offs = 0;
@@ -866,7 +870,7 @@ int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
fill_new_filp (&filp, NULL);
- dentry_src = creat_dentry ("hlink-mn", 8, hlink);
+ dentry_src = creat_dentry ("hlink-mn", 8, hlink, NULL);
memset (&filp, 0, sizeof (filp));
@@ -894,7 +898,7 @@ int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
if (*pt == '/') *pt++ = '\0';
/* FIXME. /mn/ fixed ? */
- dentry_dst = creat_dentry (start, len, NULL);
+ dentry_dst = creat_dentry (start, len, NULL, NULL);
if (dir->u.umsdos_i.i_emd_dir == 0){
/* This is a DOS directory */
@@ -917,7 +921,7 @@ int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
}
}else{
Printk (("umsdos_hlink2inode: all those iput's() frighten me /mn/. Whatabout dput() ? FIXME!\n"));
- iput (hlink); /* FIXME */
+ /* iput (hlink); / * FIXME */
}
Printk (("hlink2inode ret = %d %p -> %p\n", ret, hlink, *result));
kfree (path);
diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c
index 8ba6571eb..6cb630b1c 100644
--- a/fs/umsdos/emd.c
+++ b/fs/umsdos/emd.c
@@ -52,9 +52,11 @@ void fill_new_filp (struct file *filp, struct dentry *dentry)
*
*/
-struct dentry *creat_dentry (const char *name, const int len, struct inode *inode)
+struct dentry *creat_dentry (const char *name, const int len, struct inode *inode, struct dentry *parent)
{
- struct dentry *ret, *parent=NULL; /* FIXME /mn/: whatis parent ?? */
+/* FIXME /mn/: parent is not passed many times... if it is not, dentry should be destroyed before someone else gets to use it */
+
+ struct dentry *ret;
struct qstr qname;
if (inode)
@@ -71,10 +73,10 @@ struct dentry *creat_dentry (const char *name, const int len, struct inode *inod
if (inode) d_add (ret, inode);
-/* ret->d_inode = inode; /mn/ FIXME this was old, replaced by d_add, delete this ! */
return ret;
}
+
/*
* removes temporary dentry created by creat_dentry
*
@@ -123,7 +125,7 @@ ssize_t umsdos_file_read_kmem (struct inode *emd_dir,
set_fs (KERNEL_DS);
old_dentry=filp->f_dentry; /* save it */
- filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir);
+ filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir, NULL);
*offs = filp->f_pos;
PRINTK ((KERN_DEBUG "umsdos_file_read_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs));
@@ -138,6 +140,7 @@ ssize_t umsdos_file_read_kmem (struct inode *emd_dir,
PRINTK ((KERN_DEBUG " f_version=%ld\n", filp->f_version));
PRINTK ((KERN_DEBUG " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
+ MSDOS_I(filp->f_dentry->d_inode)->i_binary=2;
ret = fat_file_read(filp,buf,count,offs);
PRINTK ((KERN_DEBUG "fat_file_read returned with %d!\n", ret));
@@ -195,21 +198,28 @@ ssize_t umsdos_file_write_kmem_real (struct file *filp,
set_fs (KERNEL_DS);
- Printk ((KERN_ERR "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs));
- Printk ((KERN_ERR " struct dentry=%p\n", filp->f_dentry));
- Printk ((KERN_ERR " struct inode=%p\n", filp->f_dentry->d_inode));
- Printk ((KERN_ERR " inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size));
- Printk ((KERN_ERR " ofs=%ld\n",(unsigned long) *offs));
- Printk ((KERN_ERR " f_pos=%Lu\n", filp->f_pos));
- Printk ((KERN_ERR " name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name));
- Printk ((KERN_ERR " i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary ));
- Printk ((KERN_ERR " f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
- Printk ((KERN_ERR " f_owner=%d\n", filp->f_owner.uid));
- Printk ((KERN_ERR " f_version=%ld\n", filp->f_version));
- Printk ((KERN_ERR " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
-
+ Printk ((KERN_DEBUG "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs));
+ Printk ((KERN_DEBUG " struct dentry=%p\n", filp->f_dentry));
+ Printk ((KERN_DEBUG " struct inode=%p\n", filp->f_dentry->d_inode));
+ Printk ((KERN_DEBUG " inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size));
+ Printk ((KERN_DEBUG " ofs=%ld\n",(unsigned long) *offs));
+ Printk ((KERN_DEBUG " f_pos=%Lu\n", filp->f_pos));
+ Printk ((KERN_DEBUG " name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name));
+ Printk ((KERN_DEBUG " i_binary(sb)=%d\n", MSDOS_I(filp->f_dentry->d_inode)->i_binary ));
+ Printk ((KERN_DEBUG " f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
+ Printk ((KERN_DEBUG " f_owner=%d\n", filp->f_owner.uid));
+ Printk ((KERN_DEBUG " f_version=%ld\n", filp->f_version));
+ Printk ((KERN_DEBUG " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
+
+ /* note: i_binary=2 is for CVF-FAT. We put it here, instead of
+ umsdos_file_write_kmem, since it is also wise not to compress symlinks
+ (in unlikely event that they are > 512 bytes and can be compressed
+ FIXME: should we set it when reading symlink too ? */
+
+ MSDOS_I(filp->f_dentry->d_inode)->i_binary=2;
+
ret = fat_file_write (filp, buf, count, offs);
- PRINTK ((KERN_ERR "fat_file_write returned with %ld!\n", ret));
+ PRINTK ((KERN_DEBUG "fat_file_write returned with %ld!\n", ret));
set_fs (old_fs);
return ret;
@@ -231,11 +241,11 @@ ssize_t umsdos_file_write_kmem (struct inode *emd_dir,
struct dentry *old_dentry;
- Printk ((KERN_ERR " STARTED WRITE_KMEM /mn/\n"));
- Printk ((KERN_ERR " using emd=%ld\n", emd_dir->i_ino));
+ Printk ((KERN_DEBUG " STARTED WRITE_KMEM /mn/\n"));
+ Printk ((KERN_DEBUG " using emd=%ld\n", emd_dir->i_ino));
old_dentry=filp->f_dentry; /* save it */
- filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir);
+ filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir, NULL);
*offs = filp->f_pos; /* FIXME, in read_kmem also: offs is not used so why pass it ?!!! /mn/ */
@@ -500,7 +510,7 @@ int umsdos_writeentry (
fill_new_filp (&filp, NULL);
Printk (("umsdos_writeentry /mn/: entering...\n"));
- emd_dentry=creat_dentry ("wremd_mn", 8, emd_dir);
+ emd_dentry=creat_dentry ("wremd_mn", 8, emd_dir, NULL);
if (free_entry){
/* #Specification: EMD file / empty entries
@@ -650,7 +660,7 @@ static int umsdos_find (
memset (&buf.filp, 0, sizeof (buf.filp));
- dentry = creat_dentry ("umsfind-mn", 10, emd_dir);
+ dentry = creat_dentry ("umsfind-mn", 10, emd_dir, NULL);
fill_new_filp (&buf.filp, dentry);
@@ -743,7 +753,7 @@ int umsdos_newentry (
ret = umsdos_writeentry(dir,emd_dir,info,0);
Printk (("umsdos_newentry EMD ret = %d\n",ret));
}
- iput (emd_dir);
+ /* iput (emd_dir); FIXME */
return ret;
}
@@ -760,7 +770,7 @@ int umsdos_newhidden (
umsdos_parse ("..LINK",6,info);
info->entry.name_len = 0;
ret = umsdos_find (dir,info,&emd_dir);
- iput (emd_dir);
+ /* iput (emd_dir); FIXME */
if (ret == -ENOENT || ret == 0){
/* #Specification: hard link / hidden name
When a hard link is created, the original file is renamed
@@ -799,7 +809,7 @@ int umsdos_delentry (
}
}
}
- iput(emd_dir);
+ /* iput(emd_dir); FIXME */
return ret;
}
@@ -824,7 +834,7 @@ int umsdos_isempty (struct inode *dir)
/* Find an empty slot */
memset (&filp, 0, sizeof (filp));
- dentry = creat_dentry ("isempty-mn", 10, dir);
+ dentry = creat_dentry ("isempty-mn", 10, dir, NULL);
filp.f_pos = 0;
filp.f_reada = 1;
@@ -843,7 +853,7 @@ int umsdos_isempty (struct inode *dir)
break;
}
}
- iput (emd_dir);
+ /* iput (emd_dir); FIXME */
}
return ret;
}
@@ -870,7 +880,7 @@ int umsdos_findentry (
}
}
}
- iput (emd_dir);
+ /* iput (emd_dir); FIXME */
Printk (("umsdos_findentry: returning %d\n", ret));
return ret;
}
diff --git a/fs/umsdos/file.c b/fs/umsdos/file.c
index 04a3320ec..b7f58a2b9 100644
--- a/fs/umsdos/file.c
+++ b/fs/umsdos/file.c
@@ -144,3 +144,38 @@ struct inode_operations umsdos_file_inode_operations_no_bmap = {
NULL, /* smap */
};
+/* For other with larger and unaligned file system with readpage */
+struct file_operations umsdos_file_operations_readpage = {
+ NULL, /* lseek - default */
+ UMSDOS_file_read, /* read */
+ UMSDOS_file_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* poll - default */
+ NULL, /* ioctl - default */
+ generic_file_mmap, /* mmap */
+ NULL, /* no special open is needed */
+ NULL, /* release */
+ file_fsync /* fsync */
+};
+
+struct inode_operations umsdos_file_inode_operations_readpage = {
+ &umsdos_file_operations_readpage, /* 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 */
+ fat_readpage, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ UMSDOS_truncate, /* truncate */
+ NULL, /* permission */
+ NULL, /* smap */
+};
+
diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c
index e8b65558c..0238a5bd1 100644
--- a/fs/umsdos/inode.c
+++ b/fs/umsdos/inode.c
@@ -125,7 +125,7 @@ void umsdos_set_dirinfo(
Printk (("umsdos_set_dirinfo: emd_owner is %lu for dir %lu\n", emd_owner->i_ino, dir->i_ino));
inode->u.umsdos_i.i_dir_owner = dir->i_ino;
inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino;
- iput (emd_owner);
+ /* iput (emd_owner); FIXME */
inode->u.umsdos_i.pos = f_pos;
}
@@ -176,12 +176,22 @@ void umsdos_patch_inode (
if (!umsdos_isinit(inode)){
inode->u.umsdos_i.i_emd_dir = 0;
if (S_ISREG(inode->i_mode)){
- if (inode->i_op->bmap != NULL){
- Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations\n"));
- inode->i_op = &umsdos_file_inode_operations;
- }else{
- Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n"));
- inode->i_op = &umsdos_file_inode_operations_no_bmap;
+ if (MSDOS_SB(inode->i_sb)->cvf_format){
+ if (MSDOS_SB(inode->i_sb)->cvf_format->flags&CVF_USE_READPAGE){
+ Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_readpage\n"));
+ inode->i_op = &umsdos_file_inode_operations_readpage;
+ }else{
+ Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n"));
+ inode->i_op = &umsdos_file_inode_operations_no_bmap;
+ }
+ }else{
+ if (inode->i_op->bmap != NULL){
+ Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations\n"));
+ inode->i_op = &umsdos_file_inode_operations;
+ }else{
+ Printk ((KERN_DEBUG "umsdos_patch_inode /mn/: seting i_op = umsdos_file_inode_operations_no_bmap\n"));
+ inode->i_op = &umsdos_file_inode_operations_no_bmap;
+ }
}
}else if (S_ISDIR(inode->i_mode)){
if (dir != NULL){
@@ -223,7 +233,7 @@ void umsdos_patch_inode (
struct inode *emd_owner;
Printk ((KERN_WARNING "umsdos_patch_inode: /mn/ Warning: untested emd_owner thingy...\n"));
emd_owner = umsdos_emd_dir_lookup(dir,1);
- iput (emd_owner);
+ /* iput (emd_owner); FIXME */
if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner){
printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld "
,inode->i_ino,emd_owner->i_ino,inode->u.umsdos_i.i_emd_owner);
@@ -323,7 +333,7 @@ int internal_notify_change(struct inode *inode, struct iattr *attr)
{
int ret = 0;
- Printk ((KERN_ERR "UMSDOS_notify_change: /mn/ completly untested\n"));
+ PRINTK ((KERN_DEBUG "UMSDOS_notify_change: entering\n"));
if ((ret = inode_change_ok(inode, attr)) != 0)
return ret;
@@ -366,7 +376,7 @@ int internal_notify_change(struct inode *inode, struct iattr *attr)
struct dentry *emd_dentry;
loff_t offs;
- emd_dentry = creat_dentry ("notify_emd", 10, emd_owner);
+ emd_dentry = creat_dentry ("notify_emd", 10, emd_owner, NULL);
fill_new_filp (&filp, emd_dentry);
filp.f_pos = inode->u.umsdos_i.pos;
@@ -403,7 +413,7 @@ int internal_notify_change(struct inode *inode, struct iattr *attr)
EMD file. The msdos fs is not even called.
*/
}
- iput (emd_owner);
+ /* iput (emd_owner); FIXME */
}
Printk (("\n"));
}
@@ -472,7 +482,7 @@ struct super_block *UMSDOS_read_super(
PRINTK ((KERN_DEBUG "UMSDOS /mn/: sb = %p\n",sb));
res = msdos_read_super(sb,data,silent);
PRINTK ((KERN_DEBUG "UMSDOS /mn/: res = %p\n",res));
- printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-2 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE);
+ printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-3 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE);
if (res == NULL) { MOD_DEC_USE_COUNT; return NULL; }
@@ -480,7 +490,7 @@ struct super_block *UMSDOS_read_super(
res->s_op = &umsdos_sops;
Printk ((KERN_DEBUG "umsdos /mn/: here goes the iget ROOT_INO\n"));
- pseudo = iget(res,UMSDOS_ROOT_INO);
+ pseudo = iget(res,UMSDOS_ROOT_INO);
Printk ((KERN_DEBUG "umsdos_read_super %p\n",pseudo));
umsdos_setup_dir_inode (pseudo);
@@ -521,8 +531,8 @@ struct super_block *UMSDOS_read_super(
*/
struct dentry *root, *etc, *etc_rc, *init, *sbin;
- root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen(UMSDOS_PSDROOT_NAME), NULL);
- sbin = creat_dentry ("sbin", 4, NULL);
+ root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen(UMSDOS_PSDROOT_NAME), NULL, NULL);
+ sbin = creat_dentry ("sbin", 4, NULL, NULL);
Printk ((KERN_DEBUG "Mounting root\n"));
if (umsdos_real_lookup (pseudo,root)==0
@@ -531,7 +541,7 @@ struct super_block *UMSDOS_read_super(
int pseudo_ok = 0;
Printk ((KERN_DEBUG "/%s is there\n",UMSDOS_PSDROOT_NAME));
- etc = creat_dentry ("etc", 3, NULL);
+ etc = creat_dentry ("etc", 3, NULL, NULL);
/* if (umsdos_real_lookup (pseudo,"etc",3,etc)==0 */
@@ -540,8 +550,8 @@ struct super_block *UMSDOS_read_super(
Printk ((KERN_DEBUG "/%s/etc is there\n",UMSDOS_PSDROOT_NAME));
- init = creat_dentry ("init", 4, NULL);
- etc_rc = creat_dentry ("rc", 2, NULL);
+ init = creat_dentry ("init", 4, NULL, NULL);
+ etc_rc = creat_dentry ("rc", 2, NULL, NULL);
/* if ((umsdos_real_lookup (etc,"init",4,init)==0*/
if((umsdos_real_lookup(pseudo, init) == 0
@@ -585,7 +595,7 @@ struct super_block *UMSDOS_read_super(
Printk ((KERN_WARNING "umsdos_read_super /mn/: Pseudo should be iput-ed here...\n"));
- iput (pseudo); /* FIXME */
+ /* iput (pseudo); / * FIXME */
}
#endif /* disabled */
diff --git a/fs/umsdos/ioctl.c b/fs/umsdos/ioctl.c
index 7b92c49a4..b3f11ee32 100644
--- a/fs/umsdos/ioctl.c
+++ b/fs/umsdos/ioctl.c
@@ -60,6 +60,21 @@ int UMSDOS_ioctl_dir (
{
int ret = -EPERM;
int err;
+
+ /* forward non-umsdos ioctls - this hopefully doesn't cause conflicts */
+ if(cmd!=UMSDOS_GETVERSION
+ &&cmd!=UMSDOS_READDIR_DOS
+ &&cmd!=UMSDOS_READDIR_EMD
+ &&cmd!=UMSDOS_INIT_EMD
+ &&cmd!=UMSDOS_CREAT_EMD
+ &&cmd!=UMSDOS_RENAME_DOS
+ &&cmd!=UMSDOS_UNLINK_EMD
+ &&cmd!=UMSDOS_UNLINK_DOS
+ &&cmd!=UMSDOS_RMDIR_DOS
+ &&cmd!=UMSDOS_STAT_DOS
+ &&cmd!=UMSDOS_DOS_SETUP)
+ return fat_dir_ioctl(dir,filp,cmd,data);
+
/* #Specification: ioctl / acces
Only root (effective id) is allowed to do IOCTL on directory
in UMSDOS. EPERM is returned for other user.
@@ -162,7 +177,7 @@ int UMSDOS_ioctl_dir (
}
}
}
- iput (emd_dir);
+ /* iput (emd_dir); FIXME */
}else{
/* The absence of the EMD is simply seen as an EOF */
ret = 0;
@@ -182,7 +197,7 @@ int UMSDOS_ioctl_dir (
extern struct inode_operations umsdos_rdir_inode_operations;
struct inode *emd_dir = umsdos_emd_dir_lookup (dir,1);
ret = emd_dir != NULL;
- iput (emd_dir);
+ /* iput (emd_dir); FIXME */
dir->i_op = ret
? &umsdos_dir_inode_operations
@@ -225,8 +240,8 @@ int UMSDOS_ioctl_dir (
,dir
,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
*/
- old_dentry = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, NULL);
- new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL);
+ old_dentry = creat_dentry (data.dos_dirent.d_name, data.dos_dirent.d_reclen, NULL, NULL); /* FIXME: prolly should fill inode part */
+ new_dentry = creat_dentry (data.umsdos_dirent.name, data.umsdos_dirent.name_len, NULL, NULL);
ret = msdos_rename(dir,old_dentry,dir,new_dentry);
}else if (cmd == UMSDOS_UNLINK_EMD){
/* #Specification: ioctl / UMSDOS_UNLINK_EMD
@@ -297,7 +312,7 @@ int UMSDOS_ioctl_dir (
data.stat.st_ctime = inode->i_ctime;
data.stat.st_mtime = inode->i_mtime;
copy_to_user (&idata->stat,&data.stat,sizeof(data.stat));
- iput (inode);
+ /* iput (inode); FIXME */
}
}else if (cmd == UMSDOS_DOS_SETUP){
/* #Specification: ioctl / UMSDOS_DOS_SETUP
diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c
index dcea137fe..be72a9cb4 100644
--- a/fs/umsdos/namei.c
+++ b/fs/umsdos/namei.c
@@ -216,6 +216,7 @@ static int umsdos_create_any (
{
int ret;
+ struct dentry *fake;
Printk (("umsdos_create_any /mn/: create %.*s in dir=%lu - nevercreat=/", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino));
ret = umsdos_nevercreat(dir,dentry,-EEXIST);
@@ -238,17 +239,16 @@ static int umsdos_create_any (
ret = umsdos_newentry (dir,&info);
if (ret == 0){
dir->i_count++;
- /* FIXME
- ret = msdos_create (dir,info.fake.fname,info.fake.len
- ,S_IFREG|0777,result);
- */
- ret =msdos_create(dir,dentry,S_IFREG|0777);
+ fake = creat_dentry (info.fake.fname, info.fake.len, NULL, dentry->d_parent); /* create short name dentry */
+ ret = msdos_create (dir, fake, S_IFREG|0777);
if (ret == 0){
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = fake->d_inode;
umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
Printk (("inode %p[%lu], count=%d ",inode, inode->i_ino, inode->i_count));
Printk (("Creation OK: [dir %lu] %.*s pid=%d pos %ld\n", dir->i_ino,
info.fake.len, info.fake.fname, current->pid, info.f_pos));
+
+ d_instantiate(dentry, inode); /* long name also gets inode info */
}else{
/* #Specification: create / file exist in DOS
Here is a situation. Trying to create a file with
@@ -367,8 +367,8 @@ static int umsdos_rename_f(
PRINTK (("ret %d %d ",ret,new_info.fake.len));
if (ret == 0){
struct dentry *old, *new;
- old = creat_dentry (old_info.fake.fname, old_info.fake.len, NULL);
- new = creat_dentry (new_info.fake.fname, new_info.fake.len, NULL);
+ old = creat_dentry (old_info.fake.fname, old_info.fake.len, NULL, NULL);
+ new = creat_dentry (new_info.fake.fname, new_info.fake.len, NULL, NULL);
PRINTK (("msdos_rename "));
old_dir->i_count++;
@@ -471,7 +471,7 @@ static int umsdos_symlink_x(
fill_new_filp (&filp, dentry);
/* Make the inode acceptable to MSDOS FIXME */
- Printk ((KERN_ERR "umsdos_symlink_x: FIXME /mn/ Here goes the crash.. known wrong code...\n"));
+ Printk ((KERN_WARNING "umsdos_symlink_x: /mn/ Is this ok?\n"));
Printk ((KERN_WARNING " symname=%s ; dentry name=%.*s (ino=%lu)\n", symname, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino));
ret = umsdos_file_write_kmem_real (&filp, symname, len, &myofs);
/* dput(dentry); ?? where did this come from FIXME */
@@ -489,7 +489,7 @@ static int umsdos_symlink_x(
dir = NULL;
}
}
- d_instantiate(dentry,dir);
+ /* d_instantiate(dentry,dir); //already done in umsdos_create_any */
Printk (("\n"));
return ret;
}
@@ -634,7 +634,7 @@ int UMSDOS_link (
ret = -ENOMEM;
}else{
struct dentry *temp;
- temp = creat_dentry (entry.name, entry.name_len, NULL);
+ temp = creat_dentry (entry.name, entry.name_len, NULL, NULL);
Printk (("olddir[%d] ",olddir->i_count));
ret = umsdos_locate_path (oldinode,path);
Printk (("olddir[%d] ",olddir->i_count));
@@ -673,7 +673,7 @@ int UMSDOS_link (
umsdos_unlockcreate(olddir);
umsdos_unlockcreate(dir);
}
- iput (olddir);
+ /* iput (olddir); FIXME */
}
if (ret == 0){
struct iattr newattrs;
@@ -681,8 +681,10 @@ int UMSDOS_link (
newattrs.ia_valid = 0;
ret = UMSDOS_notify_change(olddentry, &newattrs);
}
- dput (olddentry);
- dput (dentry);
+
+/* dput (olddentry);
+ dput (dentry); FIXME.... */
+
Printk (("umsdos_link %d\n",ret));
return ret;
}
@@ -735,10 +737,12 @@ int UMSDOS_mkdir(
ret = umsdos_newentry (dir,&info);
Printk (("newentry %d ",ret));
if (ret == 0){
- struct dentry *temp;
- temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
+ struct dentry *temp, *tdir;
+ tdir = creat_dentry ("mkd-dir", 7, dir, NULL);
+ temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
dir->i_count++;
ret = msdos_mkdir (dir, temp, mode);
+
if (ret != 0){
umsdos_delentry (dir,&info,1);
/* #Specification: mkdir / Directory already exist in DOS
@@ -756,17 +760,22 @@ int UMSDOS_mkdir(
ret = compat_umsdos_real_lookup (dir,info.fake.fname,
info.fake.len,&subdir);
if (ret == 0){
-/* struct inode *result; FIXME /mn/ hmmm what is this supposed to be ? */
- struct dentry *tdentry;
- tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL);
-
- ret = msdos_create (subdir, tdentry,S_IFREG|0777);
+ struct dentry *tdentry, *tdsub;
+ tdsub = creat_dentry ("mkd-emd", 7, subdir, NULL);
+ tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tdsub);
+ ret = msdos_create (subdir, tdentry, S_IFREG|0777);
+ kill_dentry (tdentry); /* we don't want empty EMD file to be visible ! too bad kill_dentry does nothing at the moment :-) FIXME */
+ kill_dentry (tdsub);
+ umsdos_setup_dir_inode (subdir); /* this should setup dir so it is promoted to EMD, and EMD file is not visible inside it */
subdir = NULL;
+ d_instantiate(dentry, temp->d_inode);
/* iput (result); FIXME */
}
if (ret < 0){
printk ("UMSDOS: Can't create empty --linux-.---\n");
}
+
+
/* iput (subdir); FIXME */
}
}
@@ -774,7 +783,7 @@ int UMSDOS_mkdir(
}
}
Printk (("umsdos_mkdir %d\n",ret));
-/* dput (dentry); FIXME /mn/ */
+ /* dput (dentry); / * FIXME /mn/ */
return ret;
}
@@ -803,7 +812,7 @@ int UMSDOS_mknod(
*/
int ret = umsdos_create_any (dir,dentry,mode,rdev,0);
-/* dput(dentry); /mn/ FIXME! */
+ /* dput(dentry); / * /mn/ FIXME! */
return ret;
}
@@ -902,7 +911,9 @@ int UMSDOS_rmdir(
as possible.
*/
- int ret = umsdos_nevercreat(dir,dentry,-EPERM);
+ int ret;
+
+ ret = umsdos_nevercreat(dir,dentry,-EPERM);
if (ret == 0){
volatile struct inode *sdir;
dir->i_count++;
@@ -913,18 +924,22 @@ int UMSDOS_rmdir(
int empty;
umsdos_lockcreate(dir);
if (sdir->i_count > 1){
+ Printk ((" /mn/ rmdir: FIXME EBUSY: hmmm, i_count is %d > 1\n", sdir->i_count));
ret = -EBUSY;
}else if ((empty = umsdos_isempty (sdir)) != 0){
- struct dentry *tdentry;
- tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL);
+ struct dentry *tdentry, *tedir;
+ tedir = creat_dentry ("emd-rmd", 7, dir, NULL);
+ tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, tedir);
+ umsdos_real_lookup (dir, tdentry); /* fill inode part */
Printk (("isempty %d i_count %d ",empty,sdir->i_count));
/* 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 */
+ /* We have to remove the EMD file */
ret = msdos_unlink (sdir, tdentry);
+ Printk (("UMSDOS_rmdir: unlinking empty EMD ret=%d", ret));
sdir = NULL;
}
/* sdir must be free before msdos_rmdir() */
@@ -933,17 +948,34 @@ int UMSDOS_rmdir(
Printk (("isempty ret %d nlink %d ",ret,dir->i_nlink));
if (ret == 0){
struct umsdos_info info;
- struct dentry *temp;
+ struct dentry *temp, *tdir;
dir->i_count++;
umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info);
/* The findentry is there only to complete */
/* the mangling */
umsdos_findentry (dir,&info,2);
- temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
-
+
+ tdir = creat_dentry ("dir-rmd", 7, dir, NULL);
+ temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
+ umsdos_real_lookup (dir, temp); /* fill inode part */
+
+ Printk ((KERN_ERR " rmdir start dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb)); /* FIXME: /mn/ debug only */
+ Printk ((KERN_ERR " dentry=%.*s d_count=%d ino=%lu\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode->i_ino));
+ Printk ((KERN_ERR " d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino));
+
ret = msdos_rmdir (dir, temp);
+
+ Printk ((KERN_ERR " rmdir passed %d\n", ret)); /* FIXME: /mn/ debug only */
+ Printk ((KERN_ERR " rmdir end dir=%lu, dir->sb=%p\n", dir->i_ino, dir->i_sb));
+ Printk ((KERN_ERR " dentry=%.*s d_count=%d ino=%p\n", (int) temp->d_name.len, temp->d_name.name, temp->d_count, temp->d_inode));
+ Printk ((KERN_ERR " d_parent=%.*s d_count=%d ino=%lu\n", (int) temp->d_parent->d_name.len, temp->d_parent->d_name.name, temp->d_parent->d_count, temp->d_parent->d_inode->i_ino));
+
+ kill_dentry (tdir);
+ kill_dentry (temp);
+
if (ret == 0){
ret = umsdos_delentry (dir,&info,1);
+ d_delete (dentry);
}
}
}else{
@@ -961,7 +993,7 @@ int UMSDOS_rmdir(
umsdos_unlockcreate(dir);
}
}
- dput(dentry);
+ /* dput(dentry); FIXME /mn/ */
Printk (("umsdos_rmdir %d\n",ret));
return ret;
}
@@ -1036,13 +1068,21 @@ int UMSDOS_unlink (
if (ret == 0){
ret = umsdos_delentry (dir,&info,0);
if (ret == 0){
- struct dentry *temp;
+ struct dentry *temp, *tdir;
Printk (("Avant msdos_unlink %.*s ",info.fake.len,info.fake.fname));
- dir->i_count++;
- temp = creat_dentry (info.fake.fname, info.fake.len, NULL);
+ dir->i_count++; /* FIXME /mn/ is this needed anymore now that msdos_unlink locks dir using d_parent ? */
+ tdir = creat_dentry ("dir-del", 7, dir, NULL); /* FIXME /mn/: do we need iget(dir->i_ino) or would dir itself suffice ? */
+ temp = creat_dentry (info.fake.fname, info.fake.len, NULL, tdir);
+ umsdos_real_lookup (dir, temp); /* fill inode part */
+
ret = msdos_unlink_umsdos (dir, temp);
Printk (("msdos_unlink %.*s %o ret %d ",info.fake.len,info.fake.fname
,info.entry.mode,ret));
+
+ d_delete (dentry);
+
+ kill_dentry (tdir);
+ kill_dentry (temp);
}
}
}else{
@@ -1054,7 +1094,7 @@ int UMSDOS_unlink (
umsdos_unlockcreate(dir);
}
}
- dput(dentry);
+ /* dput(dentry); FIXME: shouldn't this be done in msdos_unlink ? */
Printk (("umsdos_unlink %d\n",ret));
return ret;
}
@@ -1140,8 +1180,9 @@ int UMSDOS_rename(
}
}
}
+ /*
dput (new_dentry);
- dput (old_dentry);
+ dput (old_dentry); FIXME /mn/ */
return ret;
}
diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c
index 7cd50e133..612002c3b 100644
--- a/fs/umsdos/rdir.c
+++ b/fs/umsdos/rdir.c
@@ -135,7 +135,7 @@ int umsdos_rlookup_x(
*/
Printk ((KERN_WARNING "umsdos_rlookup_x: do the pseudo-thingy...\n"));
ret = -ENOENT;
- iput (pseudo_root);
+ /* iput (pseudo_root); FIXME */
}else if (S_ISDIR(inode->i_mode)){
/* We must place the proper function table */
@@ -145,7 +145,7 @@ int umsdos_rlookup_x(
}
}
}
- iput (dir);
+ /* iput (dir); FIXME */
PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret));
return ret;
}
@@ -215,7 +215,7 @@ static int UMSDOS_rrmdir (
}else if (empty == 1){
/* We have to removed the EMD file */
struct dentry *temp;
- temp = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL);
+ temp = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, NULL); /* FIXME: prolly should fill inode part ? */
ret = msdos_unlink(sdir, temp);
sdir = NULL;
if (ret == 0){
@@ -226,12 +226,12 @@ static int UMSDOS_rrmdir (
}else{
ret = -ENOTEMPTY;
}
- iput (sdir);
+ /* iput (sdir); FIXME */
}
}
umsdos_unlockcreate (dir);
}
- iput (dir);
+ /* iput (dir); FIXME */
return ret;
}