summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-10-09 00:00:47 +0000
commitd6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch)
treee2be02f33984c48ec019c654051d27964e42c441 /fs
parent609d1e803baf519487233b765eb487f9ec227a18 (diff)
Merge with 2.3.19.
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.in33
-rw-r--r--fs/Makefile14
-rw-r--r--fs/adfs/super.c2
-rw-r--r--fs/affs/super.c2
-rw-r--r--fs/autofs/init.c2
-rw-r--r--fs/binfmt_aout.c64
-rw-r--r--fs/binfmt_elf.c70
-rw-r--r--fs/binfmt_em86.c19
-rw-r--r--fs/binfmt_misc.c26
-rw-r--r--fs/binfmt_script.c19
-rw-r--r--fs/buffer.c588
-rw-r--r--fs/coda/cache.c23
-rw-r--r--fs/coda/cnode.c6
-rw-r--r--fs/coda/dir.c24
-rw-r--r--fs/coda/file.c8
-rw-r--r--fs/coda/inode.c2
-rw-r--r--fs/coda/psdev.c20
-rw-r--r--fs/coda/upcall.c12
-rw-r--r--fs/dcache.c5
-rw-r--r--fs/devpts/inode.c2
-rw-r--r--fs/devpts/root.c5
-rw-r--r--fs/dquot.c4
-rw-r--r--fs/efs/super.c2
-rw-r--r--fs/exec.c154
-rw-r--r--fs/ext2/balloc.c3
-rw-r--r--fs/ext2/ialloc.c2
-rw-r--r--fs/ext2/inode.c43
-rw-r--r--fs/ext2/namei.c4
-rw-r--r--fs/ext2/super.c2
-rw-r--r--fs/fat/buffer.c300
-rw-r--r--fs/fat/cache.c23
-rw-r--r--fs/fat/cvf.c77
-rw-r--r--fs/fat/dir.c40
-rw-r--r--fs/fat/fatfs_syms.c6
-rw-r--r--fs/fat/file.c451
-rw-r--r--fs/fat/inode.c67
-rw-r--r--fs/fat/misc.c110
-rw-r--r--fs/fcntl.c126
-rw-r--r--fs/fifo.c178
-rw-r--r--fs/file.c240
-rw-r--r--fs/file_table.c21
-rw-r--r--fs/filesystems.c5
-rw-r--r--fs/hfs/super.c2
-rw-r--r--fs/inode.c2
-rw-r--r--fs/iobuf.c136
-rw-r--r--fs/ioctl.c6
-rw-r--r--fs/isofs/inode.c2
-rw-r--r--fs/lockd/clntlock.c2
-rw-r--r--fs/lockd/svclock.c11
-rw-r--r--fs/locks.c10
-rw-r--r--fs/minix/bitmap.c34
-rw-r--r--fs/minix/file.c1
-rw-r--r--fs/minix/inode.c26
-rw-r--r--fs/minix/namei.c22
-rw-r--r--fs/minix/truncate.c35
-rw-r--r--fs/msdos/msdosfs_syms.c2
-rw-r--r--fs/msdos/namei.c130
-rw-r--r--fs/namei.c27
-rw-r--r--fs/ncpfs/dir.c3
-rw-r--r--fs/ncpfs/inode.c10
-rw-r--r--fs/ncpfs/sock.c7
-rw-r--r--fs/nfs/dir.c2
-rw-r--r--fs/nfs/nfsroot.c25
-rw-r--r--fs/nfs/read.c2
-rw-r--r--fs/nfs/write.c2
-rw-r--r--fs/nfsd/vfs.c13
-rw-r--r--fs/nls/Config.in1
-rw-r--r--fs/nls/Makefile8
-rw-r--r--fs/nls/nls_base.c3
-rw-r--r--fs/nls/nls_iso8859-14.c275
-rw-r--r--fs/noquot.c2
-rw-r--r--fs/ntfs/fs.c4
-rw-r--r--fs/open.c109
-rw-r--r--fs/partitions/.cvsignore2
-rw-r--r--fs/partitions/Config.in67
-rw-r--r--fs/partitions/Makefile49
-rw-r--r--fs/partitions/acorn.c472
-rw-r--r--fs/partitions/acorn.h68
-rw-r--r--fs/partitions/amiga.c120
-rw-r--r--fs/partitions/amiga.h8
-rw-r--r--fs/partitions/atari.c177
-rw-r--r--fs/partitions/atari.h36
-rw-r--r--fs/partitions/check.c334
-rw-r--r--fs/partitions/check.h10
-rw-r--r--fs/partitions/mac.c110
-rw-r--r--fs/partitions/mac.h44
-rw-r--r--fs/partitions/msdos.c490
-rw-r--r--fs/partitions/msdos.h9
-rw-r--r--fs/partitions/osf.c86
-rw-r--r--fs/partitions/osf.h9
-rw-r--r--fs/partitions/sgi.c86
-rw-r--r--fs/partitions/sgi.h9
-rw-r--r--fs/partitions/sun.c89
-rw-r--r--fs/partitions/sun.h9
-rw-r--r--fs/partitions/ultrix.c60
-rw-r--r--fs/pipe.c428
-rw-r--r--fs/proc/array.c295
-rw-r--r--fs/proc/base.c2
-rw-r--r--fs/proc/fd.c13
-rw-r--r--fs/proc/link.c74
-rw-r--r--fs/proc/mem.c5
-rw-r--r--fs/proc/openpromfs.c8
-rw-r--r--fs/proc/proc_tty.c2
-rw-r--r--fs/proc/root.c46
-rw-r--r--fs/qnx4/inode.c46
-rw-r--r--fs/read_write.c8
-rw-r--r--fs/readdir.c2
-rw-r--r--fs/romfs/inode.c4
-rw-r--r--fs/select.c16
-rw-r--r--fs/smbfs/inode.c2
-rw-r--r--fs/stat.c14
-rw-r--r--fs/super.c15
-rw-r--r--fs/sysv/inode.c2
-rw-r--r--fs/udf/.cvsignore2
-rw-r--r--fs/udf/Makefile16
-rw-r--r--fs/udf/balloc.c441
-rw-r--r--fs/udf/crc.c178
-rw-r--r--fs/udf/dir.c296
-rw-r--r--fs/udf/directory.c332
-rw-r--r--fs/udf/file.c440
-rw-r--r--fs/udf/fsync.c110
-rw-r--r--fs/udf/ialloc.c169
-rw-r--r--fs/udf/inode.c1944
-rw-r--r--fs/udf/lowlevel.c149
-rw-r--r--fs/udf/misc.c540
-rw-r--r--fs/udf/namei.c1302
-rw-r--r--fs/udf/partition.c190
-rw-r--r--fs/udf/super.c1623
-rw-r--r--fs/udf/symlink.c189
-rw-r--r--fs/udf/truncate.c229
-rw-r--r--fs/udf/udf_i.h24
-rw-r--r--fs/udf/udf_sb.h66
-rw-r--r--fs/udf/udfdecl.h278
-rw-r--r--fs/udf/udfend.h111
-rw-r--r--fs/udf/udftime.c373
-rw-r--r--fs/udf/unicode.c447
-rw-r--r--fs/ufs/super.c2
-rw-r--r--fs/ufs/truncate.c3
-rw-r--r--fs/umsdos/Makefile2
-rw-r--r--fs/umsdos/check.c19
-rw-r--r--fs/umsdos/dir.c5
-rw-r--r--fs/umsdos/emd.c10
-rw-r--r--fs/umsdos/file.c189
-rw-r--r--fs/umsdos/inode.c18
-rw-r--r--fs/umsdos/symlink.c2
-rw-r--r--fs/vfat/namei.c32
146 files changed, 14738 insertions, 2037 deletions
diff --git a/fs/Config.in b/fs/Config.in
index a2ddc3916..9a6a53960 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -31,6 +31,11 @@ else
define_bool CONFIG_JOLIET n
fi
+tristate 'UDF filesystem support' CONFIG_UDF_FS
+if [ "$CONFIG_UDF_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' UDF read-write support (EXPERIMENTAL)' CONFIG_UDF_RW
+fi
+
tristate 'Minix fs support' CONFIG_MINIX_FS
tristate 'NTFS filesystem support (read only)' CONFIG_NTFS_FS
if [ "$CONFIG_NTFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -71,11 +76,10 @@ if [ "$CONFIG_INET" = "y" ]; then
if [ "$CONFIG_NFS_FS" = "y" -a "$CONFIG_IP_PNP" = "y" ]; then
bool ' Root file system on NFS' CONFIG_ROOT_NFS
fi
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'NFS server support' CONFIG_NFSD
- if [ "$CONFIG_NFSD" != "n" ]; then
- bool ' Emulate SUN NFS server' CONFIG_NFSD_SUN
- fi
+ # considering that RedHat-6.0 ships with this on, I guess it's not really experimental
+ tristate 'NFS server support' CONFIG_NFSD
+ if [ "$CONFIG_NFSD" != "n" ]; then
+ bool ' Emulate SUN NFS server' CONFIG_NFSD_SUN
fi
if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
define_bool CONFIG_SUNRPC y
@@ -103,24 +107,7 @@ fi
mainmenu_option next_comment
comment 'Partition Types'
-
-bool 'BSD disklabel (BSD partition tables) support' CONFIG_BSD_DISKLABEL
-bool 'Macintosh partition map support' CONFIG_MAC_PARTITION
-bool 'OSF partition table support' CONFIG_OSF_PARTITION
-bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL
-bool 'Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
-bool 'SGI disklabel support' CONFIG_SGI_DISKLABEL
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool 'Ultrix partition table support (experimental)' CONFIG_ULTRIX_PARTITION
- bool 'Unixware slices support (EXPERIMENTAL)' CONFIG_UNIXWARE_DISKLABEL
-fi
-
+source fs/partitions/Config.in
endmenu
-
-if [ "$CONFIG_AFFS_FS" != "n" ]; then
- define_bool CONFIG_AMIGA_PARTITION y
-fi
-
source fs/nls/Config.in
-
endmenu
diff --git a/fs/Makefile b/fs/Makefile
index 069b1a2a4..8bfbd050b 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -13,12 +13,14 @@ O_TARGET := fs.o
O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \
super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \
- dcache.o inode.o attr.o bad_inode.o $(BINFMTS)
+ dcache.o inode.o attr.o bad_inode.o file.o iobuf.o $(BINFMTS)
MOD_LIST_NAME := FS_MODULES
ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
hpfs sysv smbfs ncpfs ufs efs affs romfs autofs hfs lockd \
- nfsd nls devpts adfs qnx4
+ nfsd nls devpts adfs partitions qnx4 udf
+
+SUB_DIRS := partitions
ifeq ($(CONFIG_QUOTA),y)
O_OBJS += dquot.o
@@ -223,6 +225,14 @@ else
endif
endif
+ifeq ($(CONFIG_UDF_FS),y)
+SUB_DIRS += udf
+else
+ ifeq ($(CONFIG_UDF_FS),m)
+ MOD_SUB_DIRS += udf
+ endif
+endif
+
ifeq ($(CONFIG_AUTOFS_FS),y)
SUB_DIRS += autofs
else
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index e5f54f414..c8db4d2e1 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -385,7 +385,7 @@ static struct file_system_type adfs_fs_type = {
"adfs", FS_REQUIRES_DEV, adfs_read_super, NULL
};
-__initfunc(int init_adfs_fs(void))
+int __init init_adfs_fs(void)
{
return register_filesystem(&adfs_fs_type);
}
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 9084a4cf3..fe5fd1042 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -688,7 +688,7 @@ static struct file_system_type affs_fs_type = {
NULL
};
-__initfunc(int init_affs_fs(void))
+int __init init_affs_fs(void)
{
return register_filesystem(&affs_fs_type);
}
diff --git a/fs/autofs/init.c b/fs/autofs/init.c
index 2afca0547..a4c5184f2 100644
--- a/fs/autofs/init.c
+++ b/fs/autofs/init.c
@@ -34,7 +34,7 @@ void cleanup_module(void)
#else /* MODULE */
-__initfunc(int init_autofs_fs(void))
+int __init init_autofs_fs(void)
{
return register_filesystem(&autofs_fs_type);
}
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 52c1f7aab..0e5c0a609 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -31,16 +31,12 @@
static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
static int load_aout_library(int fd);
-static int aout_core_dump(long signr, struct pt_regs * regs);
+static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file);
extern void dump_thread(struct pt_regs *, struct user *);
static struct linux_binfmt aout_format = {
-#ifndef MODULE
- NULL, NULL, load_aout_binary, load_aout_library, aout_core_dump
-#else
- NULL, &__this_module, load_aout_binary, load_aout_library, aout_core_dump
-#endif
+ NULL, THIS_MODULE, load_aout_binary, load_aout_library, aout_core_dump, PAGE_SIZE
};
static void set_brk(unsigned long start, unsigned long end)
@@ -64,12 +60,12 @@ static int dump_write(struct file *file, const void *addr, int nr)
#define DUMP_WRITE(addr, nr) \
if (!dump_write(file, (void *)(addr), (nr))) \
- goto close_coredump;
+ goto end_coredump;
#define DUMP_SEEK(offset) \
if (file->f_op->llseek) { \
if (file->f_op->llseek(file,(offset),0) != (offset)) \
- goto close_coredump; \
+ goto end_coredump; \
} else file->f_pos = (offset)
/*
@@ -83,14 +79,10 @@ if (file->f_op->llseek) { \
*/
static inline int
-do_aout_core_dump(long signr, struct pt_regs * regs)
+do_aout_core_dump(long signr, struct pt_regs * regs, struct file *file)
{
- struct dentry * dentry = NULL;
- struct inode * inode = NULL;
- struct file * file;
mm_segment_t fs;
int has_dumped = 0;
- char corefile[6+sizeof(current->comm)];
unsigned long dump_start, dump_size;
struct user dump;
#if defined(__alpha__)
@@ -106,32 +98,8 @@ do_aout_core_dump(long signr, struct pt_regs * regs)
# define START_STACK(u) (u.start_stack)
#endif
- if (!current->dumpable || atomic_read(&current->mm->count) != 1)
- return 0;
- current->dumpable = 0;
-
-/* See if we have enough room to write the upage. */
- if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE)
- return 0;
fs = get_fs();
set_fs(KERNEL_DS);
- memcpy(corefile,"core.",5);
-#if 0
- memcpy(corefile+5,current->comm,sizeof(current->comm));
-#else
- corefile[4] = '\0';
-#endif
- file = filp_open(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
- if (IS_ERR(file))
- goto end_coredump;
- dentry = file->f_dentry;
- inode = dentry->d_inode;
- if (!S_ISREG(inode->i_mode))
- goto close_coredump;
- if (!inode->i_op || !inode->i_op->default_file_ops)
- goto close_coredump;
- if (!file->f_op->write)
- goto close_coredump;
has_dumped = 1;
current->flags |= PF_DUMPCORE;
strncpy(dump.u_comm, current->comm, sizeof(current->comm));
@@ -210,20 +178,18 @@ do_aout_core_dump(long signr, struct pt_regs * regs)
/* Finally dump the task struct. Not be used by gdb, but could be useful */
set_fs(KERNEL_DS);
DUMP_WRITE(current,sizeof(*current));
-close_coredump:
- filp_close(file, NULL);
end_coredump:
set_fs(fs);
return has_dumped;
}
static int
-aout_core_dump(long signr, struct pt_regs * regs)
+aout_core_dump(long signr, struct pt_regs * regs, struct file *file)
{
int retval;
MOD_INC_USE_COUNT;
- retval = do_aout_core_dump(signr, regs);
+ retval = do_aout_core_dump(signr, regs, file);
MOD_DEC_USE_COUNT;
return retval;
}
@@ -349,7 +315,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
current->personality = PER_LINUX;
#if defined(__sparc__) && !defined(__sparc_v9__)
- memcpy(&current->tss.core_exec, &ex, sizeof(struct exec));
+ memcpy(&current->thread.core_exec, &ex, sizeof(struct exec));
#endif
current->mm->end_code = ex.a_text +
@@ -587,17 +553,15 @@ load_aout_library(int fd)
}
-int __init init_aout_binfmt(void)
+static int __init init_aout_binfmt(void)
{
return register_binfmt(&aout_format);
}
-#ifdef MODULE
-int init_module(void) {
- return init_aout_binfmt();
-}
-
-void cleanup_module( void) {
+static void __exit exit_aout_binfmt(void)
+{
unregister_binfmt(&aout_format);
}
-#endif
+
+module_init(init_aout_binfmt)
+module_exit(exit_aout_binfmt)
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index e3087a18b..aa59a2f7f 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -54,7 +54,7 @@ extern void dump_thread(struct pt_regs *, struct user *);
* don't even try.
*/
#ifdef USE_ELF_CORE_DUMP
-static int elf_core_dump(long signr, struct pt_regs * regs);
+static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file);
#else
#define elf_core_dump NULL
#endif
@@ -64,11 +64,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs);
#define ELF_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1))
static struct linux_binfmt elf_format = {
-#ifndef MODULE
- NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump
-#else
- NULL, &__this_module, load_elf_binary, load_elf_library, elf_core_dump
-#endif
+ NULL, THIS_MODULE, load_elf_binary, load_elf_library, elf_core_dump, ELF_EXEC_PAGESIZE
};
static void set_brk(unsigned long start, unsigned long end)
@@ -1026,10 +1022,10 @@ static int writenote(struct memelfnote *men, struct file *file)
#define DUMP_WRITE(addr, nr) \
if (!dump_write(file, (addr), (nr))) \
- goto close_coredump;
+ goto end_coredump;
#define DUMP_SEEK(off) \
if (!dump_seek(file, (off))) \
- goto close_coredump;
+ goto end_coredump;
/*
* Actual dumper
*
@@ -1037,14 +1033,10 @@ static int writenote(struct memelfnote *men, struct file *file)
* and then they are actually written out. If we run out of core limit
* we just truncate.
*/
-static int elf_core_dump(long signr, struct pt_regs * regs)
+static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
{
int has_dumped = 0;
- struct file *file;
- struct dentry *dentry;
- struct inode *inode;
mm_segment_t fs;
- char corefile[6+sizeof(current->comm)];
int segs;
int i;
size_t size;
@@ -1058,12 +1050,6 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
elf_fpregset_t fpu; /* NT_PRFPREG */
struct elf_prpsinfo psinfo; /* NT_PRPSINFO */
- if (!current->dumpable ||
- limit < ELF_EXEC_PAGESIZE ||
- atomic_read(&current->mm->count) != 1)
- return 0;
- current->dumpable = 0;
-
#ifndef CONFIG_BINFMT_ELF
MOD_INC_USE_COUNT;
#endif
@@ -1112,27 +1098,6 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
fs = get_fs();
set_fs(KERNEL_DS);
- memcpy(corefile,"core.",5);
-#if 0
- memcpy(corefile+5,current->comm,sizeof(current->comm));
-#else
- corefile[4] = '\0';
-#endif
- file = filp_open(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
- if (IS_ERR(file))
- goto end_coredump;
- dentry = file->f_dentry;
- inode = dentry->d_inode;
- if (inode->i_nlink > 1)
- goto close_coredump; /* multiple links - don't dump */
-
- if (!S_ISREG(inode->i_mode))
- goto close_coredump;
- if (!inode->i_op || !inode->i_op->default_file_ops)
- goto close_coredump;
- if (!file->f_op->write)
- goto close_coredump;
-
has_dumped = 1;
current->flags |= PF_DUMPCORE;
@@ -1289,7 +1254,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
for(i = 0; i < numnote; i++)
if (!writenote(&notes[i], file))
- goto close_coredump;
+ goto end_coredump;
set_fs(fs);
@@ -1316,9 +1281,6 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
(off_t) file->f_pos, offset);
}
- close_coredump:
- filp_close(file, NULL);
-
end_coredump:
set_fs(fs);
#ifndef CONFIG_BINFMT_ELF
@@ -1328,26 +1290,16 @@ static int elf_core_dump(long signr, struct pt_regs * regs)
}
#endif /* USE_ELF_CORE_DUMP */
-int __init init_elf_binfmt(void)
+static int __init init_elf_binfmt(void)
{
return register_binfmt(&elf_format);
}
-#ifdef MODULE
-
-int init_module(void)
-{
- /* Install the COFF, ELF and XOUT loaders.
- * N.B. We *rely* on the table being the right size with the
- * right number of free slots...
- */
- return init_elf_binfmt();
-}
-
-
-void cleanup_module( void)
+static void __exit exit_elf_binfmt(void)
{
/* Remove the COFF and ELF loaders. */
unregister_binfmt(&elf_format);
}
-#endif
+
+module_init(init_elf_binfmt)
+module_exit(exit_elf_binfmt)
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
index f102f2dec..aa2deaf6e 100644
--- a/fs/binfmt_em86.c
+++ b/fs/binfmt_em86.c
@@ -105,25 +105,18 @@ static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
}
struct linux_binfmt em86_format = {
-#ifndef MODULE
- NULL, 0, load_em86, NULL, NULL
-#else
- NULL, &__this_module, load_em86, NULL, NULL
-#endif
+ NULL, THIS_MODULE, load_em86, NULL, NULL, 0
};
-int __init init_em86_binfmt(void)
+static int __init init_em86_binfmt(void)
{
return register_binfmt(&em86_format);
}
-#ifdef MODULE
-int init_module(void)
+static void __exit exit_em86_binfmt(void)
{
- return init_em86_binfmt();
-}
-
-void cleanup_module( void) {
unregister_binfmt(&em86_format);
}
-#endif
+
+module_init(init_em86_binfmt)
+module_exit(exit_em86_binfmt)
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 7b9cead81..6143bd5d0 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -27,8 +27,8 @@
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/ctype.h>
+#include <linux/spinlock.h>
#include <asm/uaccess.h>
-#include <asm/spinlock.h>
/*
* We should make this work with a "stub-only" /proc,
@@ -64,11 +64,7 @@ static void entry_proc_cleanup(struct binfmt_entry *e);
static int entry_proc_setup(struct binfmt_entry *e);
static struct linux_binfmt misc_format = {
-#ifndef MODULE
- NULL, 0, load_misc_binary, NULL, NULL
-#else
- NULL, &__this_module, load_misc_binary, NULL, NULL
-#endif
+ NULL, THIS_MODULE, load_misc_binary, NULL, NULL, 0
};
static struct proc_dir_entry *bm_dir = NULL;
@@ -493,7 +489,7 @@ static void bm_modcount(struct inode *inode, int fill)
}
#endif
-int __init init_misc_binfmt(void)
+static int __init init_misc_binfmt(void)
{
int error = -ENOENT;
struct proc_dir_entry *status = NULL, *reg;
@@ -528,14 +524,7 @@ cleanup_bm:
goto out;
}
-#ifdef MODULE
-EXPORT_NO_SYMBOLS;
-int init_module(void)
-{
- return init_misc_binfmt();
-}
-
-void cleanup_module(void)
+static void __exit exit_misc_binfmt(void)
{
unregister_binfmt(&misc_format);
remove_proc_entry("register", bm_dir);
@@ -543,5 +532,8 @@ void cleanup_module(void)
clear_entries();
remove_proc_entry("sys/fs/binfmt_misc", NULL);
}
-#endif
-#undef VERBOSE_STATUS
+
+EXPORT_NO_SYMBOLS;
+
+module_init(init_misc_binfmt)
+module_exit(exit_misc_binfmt)
diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c
index 8cc685aca..3dad604e3 100644
--- a/fs/binfmt_script.c
+++ b/fs/binfmt_script.c
@@ -101,25 +101,18 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
}
struct linux_binfmt script_format = {
-#ifndef MODULE
- NULL, 0, load_script, NULL, NULL
-#else
- NULL, &__this_module, load_script, NULL, NULL
-#endif
+ NULL, THIS_MODULE, load_script, NULL, NULL, 0
};
-int __init init_script_binfmt(void)
+static int __init init_script_binfmt(void)
{
return register_binfmt(&script_format);
}
-#ifdef MODULE
-int init_module(void)
+static void __exit exit_script_binfmt(void)
{
- return init_script_binfmt();
-}
-
-void cleanup_module( void) {
unregister_binfmt(&script_format);
}
-#endif
+
+module_init(init_script_binfmt)
+module_exit(exit_script_binfmt)
diff --git a/fs/buffer.c b/fs/buffer.c
index 108b385ea..c4fefe5cc 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -40,10 +40,12 @@
#include <linux/file.h>
#include <linux/init.h>
#include <linux/quotaops.h>
+#include <linux/iobuf.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/bitops.h>
+#include <asm/mmu_context.h>
#define NR_SIZES 7
static char buffersize_index[65] =
@@ -144,8 +146,8 @@ void __wait_on_buffer(struct buffer_head * bh)
atomic_inc(&bh->b_count);
add_wait_queue(&bh->b_wait, &wait);
repeat:
- tsk->state = TASK_UNINTERRUPTIBLE;
run_task_queue(&tq_disk);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
if (buffer_locked(bh)) {
schedule();
goto repeat;
@@ -225,7 +227,6 @@ repeat:
continue;
atomic_inc(&bh->b_count);
- bh->b_flushtime = 0;
spin_unlock(&lru_list_lock);
ll_rw_block(WRITE, 1, &bh);
atomic_dec(&bh->b_count);
@@ -306,7 +307,7 @@ int fsync_dev(kdev_t dev)
return sync_buffers(dev, 1);
}
-asmlinkage int sys_sync(void)
+asmlinkage long sys_sync(void)
{
fsync_dev(0);
return 0;
@@ -336,7 +337,7 @@ int file_fsync(struct file *filp, struct dentry *dentry)
return sync_buffers(dev, 1);
}
-asmlinkage int sys_fsync(unsigned int fd)
+asmlinkage long sys_fsync(unsigned int fd)
{
struct file * file;
struct dentry * dentry;
@@ -373,7 +374,7 @@ out:
return err;
}
-asmlinkage int sys_fdatasync(unsigned int fd)
+asmlinkage long sys_fdatasync(unsigned int fd)
{
struct file * file;
struct dentry * dentry;
@@ -435,7 +436,6 @@ void invalidate_buffers(kdev_t dev)
}
if (atomic_read(&bh->b_count))
continue;
- bh->b_flushtime = 0;
clear_bit(BH_Protected, &bh->b_state);
clear_bit(BH_Uptodate, &bh->b_state);
clear_bit(BH_Dirty, &bh->b_state);
@@ -650,7 +650,6 @@ void set_blocksize(kdev_t dev, int size)
clear_bit(BH_Dirty, &bh->b_state);
clear_bit(BH_Uptodate, &bh->b_state);
clear_bit(BH_Req, &bh->b_state);
- bh->b_flushtime = 0;
}
if (atomic_read(&bh->b_count) == 0) {
__remove_from_queues(bh);
@@ -676,7 +675,6 @@ static void refill_freelist(int size)
void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *dev_id)
{
bh->b_list = BUF_CLEAN;
- bh->b_flushtime = 0;
bh->b_end_io = handler;
bh->b_dev_id = dev_id;
}
@@ -700,7 +698,6 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
unsigned long flags;
struct buffer_head *tmp;
struct page *page;
- int free;
mark_buffer_uptodate(bh, uptodate);
@@ -720,7 +717,7 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
* deemed complete once all buffers have been visited
* (b_count==0) and are now unlocked. We must make sure that
* only the _last_ buffer that decrements its count is the one
- * that free's the page..
+ * that unlock the page..
*/
spin_lock_irqsave(&page_uptodate_lock, flags);
unlock_buffer(bh);
@@ -745,26 +742,15 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
/*
* Run the hooks that have to be done when a page I/O has completed.
- *
- * Note - we need to test the flags before we unlock the page, but
- * we must not actually free the page until after the unlock!
*/
if (test_and_clear_bit(PG_decr_after, &page->flags))
atomic_dec(&nr_async_pages);
- if (test_and_clear_bit(PG_free_swap_after, &page->flags))
- swap_free(page->offset);
-
- free = test_and_clear_bit(PG_free_after, &page->flags);
-
- if (page->owner != -1)
+ if (page->owner != (void *)-1)
PAGE_BUG(page);
- page->owner = (int)current;
+ page->owner = current;
UnlockPage(page);
- if (free)
- __free_page(page);
-
return;
still_busy:
@@ -790,12 +776,8 @@ struct buffer_head * getblk(kdev_t dev, int block, int size)
repeat:
bh = get_hash_table(dev, block, size);
- if (bh) {
- if (!buffer_dirty(bh)) {
- bh->b_flushtime = 0;
- }
+ if (bh)
goto out;
- }
isize = BUFSIZE_INDEX(size);
spin_lock(&free_list[isize].lock);
@@ -838,7 +820,7 @@ out:
* pressures on different devices - thus the (currently unused)
* 'dev' parameter.
*/
-int too_many_dirty_buffers;
+static int too_many_dirty_buffers;
void balance_dirty(kdev_t dev)
{
@@ -916,19 +898,21 @@ void __brelse(struct buffer_head * buf)
*/
void __bforget(struct buffer_head * buf)
{
+ /* grab the lru lock here to block bdflush. */
spin_lock(&lru_list_lock);
write_lock(&hash_table_lock);
- if (atomic_read(&buf->b_count) != 1 || buffer_locked(buf)) {
- touch_buffer(buf);
- atomic_dec(&buf->b_count);
- } else {
- atomic_set(&buf->b_count, 0);
- buf->b_state = 0;
- if (buf->b_pprev)
- __hash_unlink(buf);
- __remove_from_lru_list(buf, buf->b_list);
- put_last_free(buf);
- }
+ if (!atomic_dec_and_test(&buf->b_count) || buffer_locked(buf))
+ goto in_use;
+ if (buf->b_pprev)
+ __hash_unlink(buf);
+ write_unlock(&hash_table_lock);
+ __remove_from_lru_list(buf, buf->b_list);
+ spin_unlock(&lru_list_lock);
+ buf->b_state = 0;
+ put_last_free(buf);
+ return;
+
+ in_use:
write_unlock(&hash_table_lock);
spin_unlock(&lru_list_lock);
}
@@ -1034,13 +1018,6 @@ static __inline__ void __put_unused_buffer_head(struct buffer_head * bh)
}
}
-static void put_unused_buffer_head(struct buffer_head *bh)
-{
- spin_lock(&unused_list_lock);
- __put_unused_buffer_head(bh);
- spin_unlock(&unused_list_lock);
-}
-
/*
* Reserve NR_RESERVED buffer heads for async IO requests to avoid
* no-buffer-head deadlock. Return NULL on failure; waiting for
@@ -1113,7 +1090,6 @@ static struct buffer_head * get_unused_buffer_head(int async)
*/
static struct buffer_head * create_buffers(unsigned long page, unsigned long size, int async)
{
- DECLARE_WAITQUEUE(wait, current);
struct buffer_head *bh, *head;
long offset;
@@ -1137,7 +1113,6 @@ try_again:
bh->b_data = (char *) (page+offset);
bh->b_list = BUF_CLEAN;
- bh->b_flushtime = 0;
bh->b_end_io = end_buffer_io_bad;
}
return head;
@@ -1146,11 +1121,13 @@ try_again:
*/
no_grow:
if (head) {
+ spin_lock(&unused_list_lock);
do {
bh = head;
head = head->b_this_page;
- put_unused_buffer_head(bh);
+ __put_unused_buffer_head(bh);
} while (head);
+ spin_unlock(&unused_list_lock);
/* Wake up any waiters ... */
wake_up(&buffer_wait);
@@ -1177,14 +1154,7 @@ no_grow:
* Set our state for sleeping, then check again for buffer heads.
* This ensures we won't miss a wake_up from an interrupt.
*/
- add_wait_queue(&buffer_wait, &wait);
- current->state = TASK_UNINTERRUPTIBLE;
- if (nr_unused_buffer_heads < MAX_BUF_PER_PAGE) {
- current->policy |= SCHED_YIELD;
- schedule();
- }
- remove_wait_queue(&buffer_wait, &wait);
- current->state = TASK_RUNNING;
+ wait_event(buffer_wait, nr_unused_buffer_heads >= MAX_BUF_PER_PAGE);
goto try_again;
}
@@ -1195,12 +1165,12 @@ static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], i
if (!PageLocked(page))
BUG();
- if (page->owner != (int)current)
+ if (page->owner != current)
PAGE_BUG(page);
/*
* Allocate async buffer heads pointing to this page, just for I/O.
- * They show up in the buffer hash table and are registered in
- * page->buffers.
+ * They don't show up in the buffer hash table, but they *are*
+ * registered in page->buffers.
*/
head = create_buffers(page_address(page), size, 1);
if (page->buffers)
@@ -1250,7 +1220,7 @@ int block_flushpage(struct inode *inode, struct page *page, unsigned long offset
if (!PageLocked(page))
BUG();
if (!page->buffers)
- return 0;
+ return 1;
head = page->buffers;
bh = head;
@@ -1263,15 +1233,12 @@ int block_flushpage(struct inode *inode, struct page *page, unsigned long offset
*/
if (offset <= curr_off) {
if (buffer_mapped(bh)) {
- atomic_inc(&bh->b_count);
- wait_on_buffer(bh);
- if (bh->b_dev == B_FREE)
- BUG();
mark_buffer_clean(bh);
+ wait_on_buffer(bh);
clear_bit(BH_Uptodate, &bh->b_state);
clear_bit(BH_Mapped, &bh->b_state);
+ clear_bit(BH_Req, &bh->b_state);
bh->b_blocknr = 0;
- atomic_dec(&bh->b_count);
}
}
curr_off = next_off;
@@ -1289,11 +1256,13 @@ int block_flushpage(struct inode *inode, struct page *page, unsigned long offset
* instead.
*/
if (!offset) {
- if (!try_to_free_buffers(page))
+ if (!try_to_free_buffers(page)) {
atomic_add(PAGE_CACHE_SIZE, &buffermem);
+ return 0;
+ }
}
- return 0;
+ return 1;
}
static void create_empty_buffers(struct page *page, struct inode *inode, unsigned long blocksize)
@@ -1526,6 +1495,395 @@ out:
}
/*
+ * For moronic filesystems that do not allow holes in file.
+ * we allow offset==PAGE_SIZE, bytes==0
+ */
+
+int block_write_cont_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+{
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ unsigned long block;
+ int err, partial;
+ unsigned long blocksize, start_block, end_block;
+ unsigned long start_offset, start_bytes, end_bytes;
+ unsigned long bbits, blocks, i, len;
+ struct buffer_head *bh, *head;
+ char * target_buf, *target_data;
+ unsigned long data_offset = offset;
+
+ offset = page->offset-inode->i_size;
+ if (offset < 0)
+ offset = 0;
+ else if (offset >= data_offset)
+ offset = data_offset;
+ bytes += data_offset-offset;
+
+ target_buf = (char *)page_address(page) + offset;
+ target_data = (char *)page_address(page) + data_offset;
+
+ if (!PageLocked(page))
+ BUG();
+
+ blocksize = inode->i_sb->s_blocksize;
+ if (!page->buffers)
+ create_empty_buffers(page, inode, blocksize);
+ head = page->buffers;
+
+ bbits = inode->i_sb->s_blocksize_bits;
+ block = page->offset >> bbits;
+ blocks = PAGE_SIZE >> bbits;
+ start_block = offset >> bbits;
+ end_block = (offset + bytes - 1) >> bbits;
+ start_offset = offset & (blocksize - 1);
+ start_bytes = blocksize - start_offset;
+ if (start_bytes > bytes)
+ start_bytes = bytes;
+ end_bytes = (offset+bytes) & (blocksize - 1);
+ if (end_bytes > bytes)
+ end_bytes = bytes;
+
+ if (offset < 0 || offset > PAGE_SIZE)
+ BUG();
+ if (bytes+offset < 0 || bytes+offset > PAGE_SIZE)
+ BUG();
+ if (start_block < 0 || start_block > blocks)
+ BUG();
+ if (end_block < 0 || end_block >= blocks)
+ BUG();
+ // FIXME: currently we assume page alignment.
+ if (page->offset & (PAGE_SIZE-1))
+ BUG();
+
+ i = 0;
+ bh = head;
+ partial = 0;
+ do {
+ if (!bh)
+ BUG();
+
+ if ((i < start_block) || (i > end_block)) {
+ if (!buffer_uptodate(bh))
+ partial = 1;
+ goto skip;
+ }
+
+ /*
+ * If the buffer is not up-to-date, we need to ask the low-level
+ * FS to do something for us (we used to have assumptions about
+ * the meaning of b_blocknr etc, that's bad).
+ *
+ * If "update" is set, that means that the low-level FS should
+ * try to make sure that the block is up-to-date because we're
+ * not going to fill it completely.
+ */
+ bh->b_end_io = end_buffer_io_sync;
+ if (!buffer_mapped(bh)) {
+ err = inode->i_op->get_block(inode, block, bh, 1);
+ if (err)
+ goto out;
+ }
+
+ if (!buffer_uptodate(bh) && (start_offset || (end_bytes && (i == end_block)))) {
+ if (buffer_new(bh)) {
+ memset(bh->b_data, 0, bh->b_size);
+ } else {
+ ll_rw_block(READ, 1, &bh);
+ wait_on_buffer(bh);
+ err = -EIO;
+ if (!buffer_uptodate(bh))
+ goto out;
+ }
+ }
+
+ len = blocksize;
+ if (start_offset) {
+ len = start_bytes;
+ start_offset = 0;
+ } else if (end_bytes && (i == end_block)) {
+ len = end_bytes;
+ end_bytes = 0;
+ }
+ err = 0;
+ if (target_buf+len<=target_data)
+ memset(target_buf, 0, len);
+ else if (target_buf<target_data) {
+ memset(target_buf, 0, target_data-target_buf);
+ copy_from_user(target_data, buf,
+ len+target_buf-target_data);
+ } else
+ err = copy_from_user(target_buf, buf, len);
+ target_buf += len;
+ buf += len;
+
+ /*
+ * we dirty buffers only after copying the data into
+ * the page - this way we can dirty the buffer even if
+ * the bh is still doing IO.
+ *
+ * NOTE! This also does a direct dirty balace check,
+ * rather than relying on bdflush just waking up every
+ * once in a while. This is to catch (and slow down)
+ * the processes that write tons of buffer..
+ *
+ * Note how we do NOT want to do this in the full block
+ * case: full pages are flushed not by the people who
+ * dirtied them, but by people who need memory. And we
+ * should not penalize them for somebody else writing
+ * lots of dirty pages.
+ */
+ set_bit(BH_Uptodate, &bh->b_state);
+ if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
+ __mark_dirty(bh, 0);
+ if (too_many_dirty_buffers)
+ balance_dirty(bh->b_dev);
+ }
+
+ if (err) {
+ err = -EFAULT;
+ goto out;
+ }
+
+skip:
+ i++;
+ block++;
+ bh = bh->b_this_page;
+ } while (bh != head);
+
+ /*
+ * is this a partial write that happened to make all buffers
+ * uptodate then we can optimize away a bogus readpage() for
+ * the next read(). Here we 'discover' wether the page went
+ * uptodate as a result of this (potentially partial) write.
+ */
+ if (!partial)
+ SetPageUptodate(page);
+ return bytes;
+out:
+ ClearPageUptodate(page);
+ return err;
+}
+
+
+/*
+ * IO completion routine for a buffer_head being used for kiobuf IO: we
+ * can't dispatch the kiobuf callback until io_count reaches 0.
+ */
+
+static void end_buffer_io_kiobuf(struct buffer_head *bh, int uptodate)
+{
+ struct kiobuf *kiobuf;
+
+ mark_buffer_uptodate(bh, uptodate);
+
+ kiobuf = bh->b_kiobuf;
+ if (atomic_dec_and_test(&kiobuf->io_count))
+ kiobuf->end_io(kiobuf);
+ if (!uptodate)
+ kiobuf->errno = -EIO;
+}
+
+
+/*
+ * For brw_kiovec: submit a set of buffer_head temporary IOs and wait
+ * for them to complete. Clean up the buffer_heads afterwards.
+ */
+
+#define dprintk(x...)
+
+static int do_kio(struct kiobuf *kiobuf,
+ int rw, int nr, struct buffer_head *bh[], int size)
+{
+ int iosize;
+ int i;
+ struct buffer_head *tmp;
+
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+
+ dprintk ("do_kio start %d\n", rw);
+
+ if (rw == WRITE)
+ rw = WRITERAW;
+ atomic_add(nr, &kiobuf->io_count);
+ kiobuf->errno = 0;
+ ll_rw_block(rw, nr, bh);
+
+ kiobuf_wait_for_io(kiobuf);
+
+ spin_lock(&unused_list_lock);
+
+ iosize = 0;
+ for (i = nr; --i >= 0; ) {
+ iosize += size;
+ tmp = bh[i];
+ if (!buffer_uptodate(tmp)) {
+ /* We are traversing bh'es in reverse order so
+ clearing iosize on error calculates the
+ amount of IO before the first error. */
+ iosize = 0;
+ }
+ __put_unused_buffer_head(tmp);
+ }
+
+ spin_unlock(&unused_list_lock);
+
+ dprintk ("do_kio end %d %d\n", iosize, err);
+
+ if (iosize)
+ return iosize;
+ if (kiobuf->errno)
+ return kiobuf->errno;
+ return -EIO;
+}
+
+/*
+ * Start I/O on a physical range of kernel memory, defined by a vector
+ * of kiobuf structs (much like a user-space iovec list).
+ *
+ * The kiobuf must already be locked for IO. IO is submitted
+ * asynchronously: you need to check page->locked, page->uptodate, and
+ * maybe wait on page->wait.
+ *
+ * It is up to the caller to make sure that there are enough blocks
+ * passed in to completely map the iobufs to disk.
+ */
+
+int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
+ kdev_t dev, unsigned long b[], int size, int bmap)
+{
+ int err;
+ int length;
+ int transferred;
+ int i;
+ int bufind;
+ int pageind;
+ int bhind;
+ int offset;
+ unsigned long blocknr;
+ struct kiobuf * iobuf = NULL;
+ unsigned long page;
+ struct page * map;
+ struct buffer_head *tmp, *bh[KIO_MAX_SECTORS];
+
+ if (!nr)
+ return 0;
+
+ /*
+ * First, do some alignment and validity checks
+ */
+ for (i = 0; i < nr; i++) {
+ iobuf = iovec[i];
+ if ((iobuf->offset & (size-1)) ||
+ (iobuf->length & (size-1)))
+ return -EINVAL;
+ if (!iobuf->locked)
+ panic("brw_kiovec: iobuf not locked for I/O");
+ if (!iobuf->nr_pages)
+ panic("brw_kiovec: iobuf not initialised");
+ }
+
+ /* DEBUG */
+#if 0
+ return iobuf->length;
+#endif
+ dprintk ("brw_kiovec: start\n");
+
+ /*
+ * OK to walk down the iovec doing page IO on each page we find.
+ */
+ bufind = bhind = transferred = err = 0;
+ for (i = 0; i < nr; i++) {
+ iobuf = iovec[i];
+ offset = iobuf->offset;
+ length = iobuf->length;
+ dprintk ("iobuf %d %d %d\n", offset, length, size);
+
+ for (pageind = 0; pageind < iobuf->nr_pages; pageind++) {
+ page = iobuf->pagelist[pageind];
+ map = iobuf->maplist[pageind];
+ if (map && PageBIGMEM(map)) {
+ err = -EIO;
+ goto error;
+ }
+
+ while (length > 0) {
+ blocknr = b[bufind++];
+ tmp = get_unused_buffer_head(0);
+ if (!tmp) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ tmp->b_dev = B_FREE;
+ tmp->b_size = size;
+ tmp->b_data = (char *) (page + offset);
+ tmp->b_this_page = tmp;
+
+ init_buffer(tmp, end_buffer_io_kiobuf, NULL);
+ tmp->b_dev = dev;
+ tmp->b_blocknr = blocknr;
+ tmp->b_state = 1 << BH_Mapped;
+ tmp->b_kiobuf = iobuf;
+
+ if (rw == WRITE) {
+ set_bit(BH_Uptodate, &tmp->b_state);
+ set_bit(BH_Dirty, &tmp->b_state);
+ }
+
+ dprintk ("buffer %d (%d) at %p\n",
+ bhind, tmp->b_blocknr, tmp->b_data);
+ bh[bhind++] = tmp;
+ length -= size;
+ offset += size;
+
+ /*
+ * Start the IO if we have got too much
+ */
+ if (bhind >= KIO_MAX_SECTORS) {
+ err = do_kio(iobuf, rw, bhind, bh, size);
+ if (err >= 0)
+ transferred += err;
+ else
+ goto finished;
+ bhind = 0;
+ }
+
+ if (offset >= PAGE_SIZE) {
+ offset = 0;
+ break;
+ }
+ } /* End of block loop */
+ } /* End of page loop */
+ } /* End of iovec loop */
+
+ /* Is there any IO still left to submit? */
+ if (bhind) {
+ err = do_kio(iobuf, rw, bhind, bh, size);
+ if (err >= 0)
+ transferred += err;
+ else
+ goto finished;
+ }
+
+ finished:
+ dprintk ("brw_kiovec: end (%d, %d)\n", transferred, err);
+ if (transferred)
+ return transferred;
+ return err;
+
+ error:
+ /* We got an error allocation the bh'es. Just free the current
+ buffer_heads and exit. */
+ spin_lock(&unused_list_lock);
+ for (i = bhind; --i >= 0; ) {
+ __put_unused_buffer_head(bh[bhind]);
+ }
+ spin_unlock(&unused_list_lock);
+ goto finished;
+}
+
+/*
* Start I/O on a page.
* This function expects the page to be locked and may return
* before I/O is complete. You then have to check page->locked,
@@ -1556,7 +1914,7 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
}
if (!page->buffers)
BUG();
- page->owner = -1;
+ page->owner = (void *)-1;
head = page->buffers;
bh = head;
@@ -1605,7 +1963,7 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
} else {
if (!nr && rw == READ) {
SetPageUptodate(page);
- page->owner = (int)current;
+ page->owner = current;
UnlockPage(page);
}
if (nr && (rw == WRITE))
@@ -1639,8 +1997,7 @@ int block_read_full_page(struct file * file, struct page * page)
blocks = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
iblock = page->offset >> inode->i_sb->s_blocksize_bits;
- page->owner = -1;
- head = page->buffers;
+ page->owner = (void *)-1;
bh = head;
nr = 0;
@@ -1674,7 +2031,7 @@ int block_read_full_page(struct file * file, struct page * page)
* uptodate as well.
*/
SetPageUptodate(page);
- page->owner = (int)current;
+ page->owner = current;
UnlockPage(page);
}
return 0;
@@ -1687,6 +2044,7 @@ int block_read_full_page(struct file * file, struct page * page)
static int grow_buffers(int size)
{
unsigned long page;
+ struct page * page_map;
struct buffer_head *bh, *tmp;
struct buffer_head * insert_point;
int isize;
@@ -1699,10 +2057,8 @@ static int grow_buffers(int size)
if (!(page = __get_free_page(GFP_BUFFER)))
return 0;
bh = create_buffers(page, size, 0);
- if (!bh) {
- free_page(page);
- return 0;
- }
+ if (!bh)
+ goto no_buffer_head;
isize = BUFSIZE_INDEX(size);
@@ -1729,9 +2085,15 @@ static int grow_buffers(int size)
free_list[isize].list = bh;
spin_unlock(&free_list[isize].lock);
- mem_map[MAP_NR(page)].buffers = bh;
+ page_map = mem_map + MAP_NR(page);
+ page_map->buffers = bh;
+ lru_cache_add(page_map);
atomic_add(PAGE_SIZE, &buffermem);
return 1;
+
+no_buffer_head:
+ free_page(page);
+ return 0;
}
/*
@@ -1940,7 +2302,6 @@ static int sync_old_buffers(void)
continue;
/* OK, now we are committed to write it out. */
- bh->b_flushtime = 0;
atomic_inc(&bh->b_count);
spin_unlock(&lru_list_lock);
ll_rw_block(WRITE, 1, &bh);
@@ -1954,48 +2315,52 @@ static int sync_old_buffers(void)
return 0;
}
-
/* This is the interface to bdflush. As we get more sophisticated, we can
* pass tuning parameters to this "process", to adjust how it behaves.
* We would want to verify each parameter, however, to make sure that it
* is reasonable. */
-asmlinkage int sys_bdflush(int func, long data)
+asmlinkage long sys_bdflush(int func, long data)
{
- int i, error = -EPERM;
-
if (!capable(CAP_SYS_ADMIN))
- goto out;
+ return -EPERM;
if (func == 1) {
- error = sync_old_buffers();
- goto out;
+ int error;
+ struct mm_struct *user_mm;
+
+ /*
+ * bdflush will spend all of it's time in kernel-space,
+ * without touching user-space, so we can switch it into
+ * 'lazy TLB mode' to reduce the cost of context-switches
+ * to and from bdflush.
+ */
+ user_mm = start_lazy_tlb();
+ error = sync_old_buffers();
+ end_lazy_tlb(user_mm);
+ return error;
}
/* Basically func 1 means read param 1, 2 means write param 1, etc */
if (func >= 2) {
- i = (func-2) >> 1;
- error = -EINVAL;
- if (i < 0 || i >= N_PARAM)
- goto out;
- if((func & 1) == 0) {
- error = put_user(bdf_prm.data[i], (int*)data);
- goto out;
+ int i = (func-2) >> 1;
+ if (i >= 0 && i < N_PARAM) {
+ if ((func & 1) == 0)
+ return put_user(bdf_prm.data[i], (int*)data);
+
+ if (data >= bdflush_min[i] && data <= bdflush_max[i]) {
+ bdf_prm.data[i] = data;
+ return 0;
+ }
}
- if (data < bdflush_min[i] || data > bdflush_max[i])
- goto out;
- bdf_prm.data[i] = data;
- error = 0;
- goto out;
- };
+ return -EINVAL;
+ }
/* Having func 0 used to launch the actual bdflush and then never
* return (unless explicitly killed). We return zero here to
* remain semi-compatible with present update(8) programs.
*/
- error = 0;
-out:
- return error;
+ return 0;
}
/*
@@ -2060,7 +2425,6 @@ int bdflush(void * unused)
major = MAJOR(bh->b_dev);
written++;
- bh->b_flushtime = 0;
/*
* For the loop major we can try to do asynchronous writes,
@@ -2068,12 +2432,7 @@ int bdflush(void * unused)
*/
atomic_inc(&bh->b_count);
spin_unlock(&lru_list_lock);
- if (major == LOOP_MAJOR && written > 1) {
- ll_rw_block(WRITEA, 1, &bh);
- if (buffer_dirty(bh))
- --written;
- } else
- ll_rw_block(WRITE, 1, &bh);
+ ll_rw_block(WRITE, 1, &bh);
atomic_dec(&bh->b_count);
goto repeat;
}
@@ -2097,3 +2456,12 @@ int bdflush(void * unused)
}
}
}
+
+static int __init bdflush_init(void)
+{
+ kernel_thread(bdflush, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+ return 0;
+}
+
+module_init(bdflush_init)
+
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index d3412e52c..fa8a66e0c 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -65,7 +65,7 @@ static void coda_ccremove(struct coda_cache *el)
if ( ! list_empty(&el->cc_cclist) )
list_del(&el->cc_cclist);
else
- printk("coda_cnremove: loose cc entry!");
+ printk("coda_ccremove: loose cc entry!");
}
/* remove a cache entry from the inode's list */
@@ -139,7 +139,7 @@ void coda_cache_enter(struct inode *inode, int mask)
/* remove all cached acl matches from an inode */
void coda_cache_clear_inode(struct inode *inode)
{
- struct list_head *lh, *le;
+ struct list_head *le;
struct coda_inode_info *cii;
struct coda_cache *cc;
ENTRY;
@@ -150,9 +150,10 @@ void coda_cache_clear_inode(struct inode *inode)
}
cii = ITOC(inode);
- lh = le = &cii->c_cnhead;
- while ( (le = le->next ) != lh ) {
+ le = cii->c_cnhead.next;
+ while ( le != &cii->c_cnhead ) {
cc = list_entry(le, struct coda_cache, cc_cnlist);
+ le = le->next;
coda_cnremove(cc);
coda_ccremove(cc);
CODA_FREE(cc, sizeof(*cc));
@@ -162,7 +163,7 @@ void coda_cache_clear_inode(struct inode *inode)
/* remove all acl caches */
void coda_cache_clear_all(struct super_block *sb)
{
- struct list_head *lh, *le;
+ struct list_head *le;
struct coda_cache *cc;
struct coda_sb_info *sbi = coda_sbp(sb);
@@ -174,9 +175,10 @@ void coda_cache_clear_all(struct super_block *sb)
if ( list_empty(&sbi->sbi_cchead) )
return;
- lh = le = &sbi->sbi_cchead;
- while ( (le = le->next ) != lh ) {
+ le = sbi->sbi_cchead.next;
+ while ( le != &sbi->sbi_cchead ) {
cc = list_entry(le, struct coda_cache, cc_cclist);
+ le = le->next;
coda_cnremove(cc);
coda_ccremove(cc);
CODA_FREE(cc, sizeof(*cc));
@@ -186,7 +188,7 @@ void coda_cache_clear_all(struct super_block *sb)
/* remove all acl caches for a principal */
void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred)
{
- struct list_head *lh, *le;
+ struct list_head *le;
struct coda_cache *cc;
struct coda_sb_info *sbi = coda_sbp(sb);
@@ -198,9 +200,10 @@ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred)
if (list_empty(&sbi->sbi_cchead))
return;
- lh = le = &sbi->sbi_cchead;
- while ( (le = le->next ) != lh ) {
+ le = sbi->sbi_cchead.next;
+ while ( le != &sbi->sbi_cchead ) {
cc = list_entry(le, struct coda_cache, cc_cclist);
+ le = le->next;
if ( coda_cred_eq(&cc->cc_cred, cred)) {
coda_cnremove(cc);
coda_ccremove(cc);
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index ffae7746f..faa983e0f 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -108,10 +108,10 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
if ( coda_f2i(fid) != ino ) {
if ( !coda_fid_is_weird(fid) )
printk("Coda: unknown weird fid: ino %ld, fid %s."
- "Tell Peter.\n", ino, coda_f2s(&cnp->c_fid));
+ "Tell Peter.\n", (long)ino, coda_f2s(&cnp->c_fid));
list_add(&cnp->c_volrootlist, &sbi->sbi_volroothead);
CDEBUG(D_UPCALL, "Added %ld ,%s to volroothead\n",
- ino, coda_f2s(&cnp->c_fid));
+ (long)ino, coda_f2s(&cnp->c_fid));
}
coda_fill_inode(*inode, &attr);
@@ -199,7 +199,7 @@ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
inode = iget(sb, nr);
if ( !inode ) {
printk("coda_fid_to_inode: null from iget, sb %p, nr %ld.\n",
- sb, nr);
+ sb, (long)nr);
return NULL;
}
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 10b1cb171..883e34a91 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -125,12 +125,12 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry)
if ( length > CODA_MAXNAMLEN ) {
printk("name too long: lookup, %s (%*s)\n",
- coda_f2s(&dircnp->c_fid), length, name);
+ coda_f2s(&dircnp->c_fid), (int)length, name);
return ERR_PTR(-ENAMETOOLONG);
}
- CDEBUG(D_INODE, "name %s, len %d in ino %ld, fid %s\n",
- name, length, dir->i_ino, coda_f2s(&dircnp->c_fid));
+ CDEBUG(D_INODE, "name %s, len %ld in ino %ld, fid %s\n",
+ name, (long)length, dir->i_ino, coda_f2s(&dircnp->c_fid));
/* control object, create inode on the fly */
if (coda_isroot(dir) && coda_iscontrol(name, length)) {
@@ -157,7 +157,7 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry)
return ERR_PTR(error);
} else if (error != -ENOENT) {
CDEBUG(D_INODE, "error for %s(%*s)%d\n",
- coda_f2s(&dircnp->c_fid), length, name, error);
+ coda_f2s(&dircnp->c_fid), (int)length, name, error);
return ERR_PTR(error);
}
CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n",
@@ -504,10 +504,10 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
old_cnp = ITOC(old_dir);
new_cnp = ITOC(new_dir);
- CDEBUG(D_INODE, "old: %s, (%d length, %d strlen), new: %s"
- "(%d length, %d strlen).old:d_count: %d, new:d_count: %d\n",
- old_name, old_length, strlen(old_name), new_name, new_length,
- strlen(new_name),old_dentry->d_count, new_dentry->d_count);
+ CDEBUG(D_INODE, "old: %s, (%d length, %ld strlen), new: %s"
+ "(%d length, %ld strlen).old:d_count: %d, new:d_count: %d\n",
+ old_name, old_length, (long)strlen(old_name), new_name, new_length,
+ (long)strlen(new_name),old_dentry->d_count, new_dentry->d_count);
/* the C library will do unlink/create etc */
if ( coda_crossvol_rename == 0 &&
@@ -594,12 +594,12 @@ int coda_open(struct inode *i, struct file *f)
error = venus_open(i->i_sb, &(cnp->c_fid), coda_flags, &ino, &dev);
if (error) {
CDEBUG(D_FILE, "venus: dev %d, inode %ld, out->result %d\n",
- dev, ino, error);
+ dev, (long)ino, error);
return error;
}
/* coda_upcall returns ino number of cached object, get inode */
- CDEBUG(D_FILE, "cache file dev %d, ino %ld\n", dev, ino);
+ CDEBUG(D_FILE, "cache file dev %d, ino %ld\n", dev, (long)ino);
error = coda_inode_grab(dev, ino, &cont_inode);
if ( error || !cont_inode ){
@@ -622,9 +622,9 @@ int coda_open(struct inode *i, struct file *f)
CDEBUG(D_FILE, "result %d, coda i->i_count is %d for ino %ld\n",
error, i->i_count, i->i_ino);
- CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %x\n",
+ CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %p\n",
cnp->c_ovp->i_ino, cnp->c_ovp->i_count,
- (int)(cnp->c_ovp->i_op));
+ (cnp->c_ovp->i_op));
EXIT;
return 0;
}
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 7e83ea954..378c4f7a6 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -155,8 +155,8 @@ static ssize_t coda_file_read(struct file *coda_file, char *buff,
result = cont_file.f_op->read(&cont_file , buff, count,
&(cont_file.f_pos));
- CDEBUG(D_FILE, "ops at %x result %d, count %d, position: %d\n",
- (int)cont_file.f_op, result, count, (int)cont_file.f_pos);
+ CDEBUG(D_FILE, "ops at %p result %d, count %ld, position: %d\n",
+ cont_file.f_op, result, (long)count, (int)cont_file.f_pos);
coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file);
return result;
@@ -292,10 +292,10 @@ int coda_inode_grab(dev_t dev, ino_t ino, struct inode **ind)
if ( *ind == NULL ) {
printk("coda_inode_grab: iget(dev: %d, ino: %ld)
- returns NULL.\n", dev, ino);
+ returns NULL.\n", dev, (long)ino);
return -ENOENT;
}
- CDEBUG(D_FILE, "ino: %ld, ops at %x\n", ino, (int)(*ind)->i_op);
+ CDEBUG(D_FILE, "ino: %ld, ops at %p\n", (long)ino, (*ind)->i_op);
return 0;
}
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 604e906a2..e2f2931b1 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -203,7 +203,7 @@ static void coda_delete_inode(struct inode *inode)
coda_cache_clear_inode(inode);
CDEBUG(D_DOWNCALL, "clearing inode: %ld, %x\n", inode->i_ino, cii->c_flags);
- inode->u.generic_ip = NULL;
+ inode->u.coda_i.c_magic = 0;
clear_inode(inode);
EXIT;
}
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index abef74563..330b634a3 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -98,8 +98,8 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
if (copy_from_user(&hdr, buf, 2 * sizeof(u_long)))
return -EFAULT;
- CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%ld,%ld), count %d\n",
- current->pid, hdr.opcode, hdr.unique, count);
+ CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%ld,%ld), count %ld\n",
+ current->pid, hdr.opcode, hdr.unique, (long)count);
if (DOWNCALL(hdr.opcode)) {
struct super_block *sb = NULL;
@@ -160,8 +160,8 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
/* move data into response buffer. */
if (req->uc_outSize < count) {
- printk("psdev_write: too much cnt: %d, cnt: %d, opc: %ld, uniq: %ld.\n",
- req->uc_outSize, count, hdr.opcode, hdr.unique);
+ printk("psdev_write: too much cnt: %d, cnt: %ld, opc: %ld, uniq: %ld.\n",
+ req->uc_outSize, (long)count, hdr.opcode, hdr.unique);
count = req->uc_outSize; /* don't have more space! */
}
if (copy_from_user(req->uc_data, buf, count))
@@ -172,8 +172,8 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
req->uc_flags |= REQ_WRITE;
CDEBUG(D_PSDEV,
- "Found! Count %d for (opc,uniq)=(%ld,%ld), upc_req at %x\n",
- count, hdr.opcode, hdr.unique, (int)&req);
+ "Found! Count %ld for (opc,uniq)=(%ld,%ld), upc_req at %p\n",
+ (long)count, hdr.opcode, hdr.unique, &req);
wake_up(&req->uc_sleep);
return(count);
@@ -190,7 +190,7 @@ static ssize_t coda_psdev_read(struct file * file, char * buf,
struct upc_req *req;
int result = count ;
- CDEBUG(D_PSDEV, "count %d\n", count);
+ CDEBUG(D_PSDEV, "count %ld\n", (long)count);
if (list_empty(&(vcp->vc_pending))) {
return -1;
}
@@ -203,8 +203,8 @@ static ssize_t coda_psdev_read(struct file * file, char * buf,
result = req->uc_inSize;
if (count < req->uc_inSize) {
- printk ("psdev_read: Venus read %d bytes of %d in message\n",
- count, req->uc_inSize);
+ printk ("psdev_read: Venus read %ld bytes of %d in message\n",
+ (long)count, req->uc_inSize);
}
if ( copy_to_user(buf, req->uc_data, result))
@@ -334,7 +334,7 @@ static struct file_operations coda_psdev_fops = {
-__initfunc(int init_coda(void))
+int __init init_coda(void)
{
int status;
printk(KERN_INFO "Coda Kernel/Venus communications, v4.6.0, braam@cs.cmu.edu\n");
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 62fd62e35..9aecd8a6e 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -625,9 +625,9 @@ static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
add_wait_queue(&vmp->uc_sleep, &wait);
for (;;) {
if ( coda_hard == 0 )
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
else
- current->state = TASK_UNINTERRUPTIBLE;
+ set_current_state(TASK_UNINTERRUPTIBLE);
/* got a reply */
if ( vmp->uc_flags & REQ_WRITE )
@@ -710,8 +710,8 @@ ENTRY;
/* Append msg to pending queue and poke Venus. */
list_add(&(req->uc_chain), vcommp->vc_pending.prev);
CDEBUG(D_UPCALL,
- "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %x.zzz.\n",
- current->pid, req->uc_opcode, req->uc_unique, (int)req);
+ "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %p.zzz.\n",
+ current->pid, req->uc_opcode, req->uc_unique, req);
wake_up_interruptible(&vcommp->vc_waitq);
/* We can be interrupted while we wait for Venus to process
@@ -731,8 +731,8 @@ ENTRY;
req->uc_opcode, jiffies - req->uc_posttime,
req->uc_unique, req->uc_outSize);
CDEBUG(D_UPCALL,
- "..process %d woken up by Venus for req at 0x%x, data at %x\n",
- current->pid, (int)req, (int)req->uc_data);
+ "..process %d woken up by Venus for req at %p, data at %p\n",
+ current->pid, req, req->uc_data);
if (vcommp->vc_pid) { /* i.e. Venus is still alive */
/* Op went through, interrupt or not... */
if (req->uc_flags & REQ_WRITE) {
diff --git a/fs/dcache.c b/fs/dcache.c
index 0d7cf9c9e..cbdfcfaf5 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -20,6 +20,7 @@
#include <linux/malloc.h>
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
@@ -473,9 +474,11 @@ void shrink_dcache_memory(int priority, unsigned int gfp_mask)
{
if (gfp_mask & __GFP_IO) {
int count = 0;
+ lock_kernel();
if (priority)
count = dentry_stat.nr_unused / priority;
prune_dcache(count);
+ unlock_kernel();
}
}
@@ -813,7 +816,7 @@ char * d_path(struct dentry *dentry, char *buffer, int buflen)
* return NULL;
* }
*/
-asmlinkage int sys_getcwd(char *buf, unsigned long size)
+asmlinkage long sys_getcwd(char *buf, unsigned long size)
{
int error;
struct dentry *pwd = current->fs->pwd;
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index bad4281ff..b11cae5ba 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -348,7 +348,7 @@ void devpts_pty_kill(int number)
}
}
-__initfunc(int init_devpts_fs(void))
+int __init init_devpts_fs(void)
{
return register_filesystem(&devpts_fs_type);
diff --git a/fs/devpts/root.c b/fs/devpts/root.c
index 9b5408235..5b5948e80 100644
--- a/fs/devpts/root.c
+++ b/fs/devpts/root.c
@@ -152,10 +152,9 @@ static struct dentry *devpts_root_lookup(struct inode * dir, struct dentry * den
unsigned int nentry = *p++ - '0';
if ( nentry > 9 )
return NULL;
- nentry += entry * 10;
- if (nentry < entry)
+ if ( entry >= ~0U/10 )
return NULL;
- entry = nentry;
+ entry = nentry + entry * 10;
}
}
diff --git a/fs/dquot.c b/fs/dquot.c
index 9dfbac082..d39a95b2c 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -199,7 +199,7 @@ static void __wait_on_dquot(struct dquot *dquot)
add_wait_queue(&dquot->dq_wait, &wait);
repeat:
- current->state = TASK_UNINTERRUPTIBLE;
+ set_current_state(TASK_UNINTERRUPTIBLE);
if (dquot->dq_flags & DQ_LOCKED) {
schedule();
goto repeat;
@@ -1337,7 +1337,7 @@ cleanup:
* calls. Maybe we need to add the process quotas etc. in the future,
* but we probably should use rlimits for that.
*/
-asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
+asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
{
int cmds = 0, type = 0, flags = 0;
kdev_t dev;
diff --git a/fs/efs/super.c b/fs/efs/super.c
index 929c9c4f1..df0f167cb 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -32,7 +32,7 @@ static struct super_operations efs_superblock_operations = {
NULL /* remount */
};
-__initfunc(int init_efs_fs(void)) {
+int __init init_efs_fs(void) {
return register_filesystem(&efs_fs_type);
}
diff --git a/fs/exec.c b/fs/exec.c
index be92bb62c..4d3295137 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -50,36 +50,6 @@
static struct linux_binfmt *formats = (struct linux_binfmt *) NULL;
-void __init binfmt_setup(void)
-{
-#ifdef CONFIG_BINFMT_MISC
- init_misc_binfmt();
-#endif
-
-#ifdef CONFIG_BINFMT_ELF
- init_elf_binfmt();
-#endif
-
-#ifdef CONFIG_BINFMT_ELF32
- init_elf32_binfmt();
-#endif
-
-#ifdef CONFIG_BINFMT_AOUT
- init_aout_binfmt();
-#endif
-
-#ifdef CONFIG_BINFMT_AOUT32
- init_aout32_binfmt();
-#endif
-
-#ifdef CONFIG_BINFMT_EM86
- init_em86_binfmt();
-#endif
-
- /* This cannot be configured out of the kernel */
- init_script_binfmt();
-}
-
int register_binfmt(struct linux_binfmt * fmt)
{
struct linux_binfmt ** tmp = &formats;
@@ -98,7 +68,6 @@ int register_binfmt(struct linux_binfmt * fmt)
return 0;
}
-#ifdef CONFIG_MODULES
int unregister_binfmt(struct linux_binfmt * fmt)
{
struct linux_binfmt ** tmp = &formats;
@@ -112,7 +81,6 @@ int unregister_binfmt(struct linux_binfmt * fmt)
}
return -EINVAL;
}
-#endif /* CONFIG_MODULES */
/* N.B. Error returns must be < 0 */
int open_dentry(struct dentry * dentry, int mode)
@@ -167,7 +135,7 @@ out:
*
* Also note that we take the address to load from from the file itself.
*/
-asmlinkage int sys_uselib(const char * library)
+asmlinkage long sys_uselib(const char * library)
{
int fd, retval;
struct file * file;
@@ -306,7 +274,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
mpnt->vm_ops = NULL;
mpnt->vm_offset = 0;
mpnt->vm_file = NULL;
- mpnt->vm_pte = 0;
+ mpnt->vm_private_data = NULL;
insert_vm_struct(current->mm, mpnt);
current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
}
@@ -366,54 +334,33 @@ end_readexec:
static int exec_mmap(void)
{
struct mm_struct * mm, * old_mm;
- int retval, nr;
- if (atomic_read(&current->mm->count) == 1) {
- flush_cache_mm(current->mm);
+ old_mm = current->mm;
+ if (old_mm && atomic_read(&old_mm->mm_users) == 1) {
+ flush_cache_mm(old_mm);
mm_release();
- release_segments(current->mm);
- exit_mmap(current->mm);
- flush_tlb_mm(current->mm);
+ exit_mmap(old_mm);
+ flush_tlb_mm(old_mm);
return 0;
}
- retval = -ENOMEM;
mm = mm_alloc();
- if (!mm)
- goto fail_nomem;
-
- mm->cpu_vm_mask = (1UL << smp_processor_id());
- mm->total_vm = 0;
- mm->rss = 0;
- /*
- * Make sure we have a private ldt if needed ...
- */
- nr = current->tarray_ptr - &task[0];
- copy_segments(nr, current, mm);
-
- old_mm = current->mm;
- current->mm = mm;
- retval = new_page_tables(current);
- if (retval)
- goto fail_restore;
- activate_context(current);
- up(&mm->mmap_sem);
- mm_release();
- mmput(old_mm);
- return 0;
+ if (mm) {
+ struct mm_struct *active_mm = current->active_mm;
- /*
- * Failure ... restore the prior mm_struct.
- */
-fail_restore:
- current->mm = old_mm;
- /* restore the ldt for this task */
- copy_segments(nr, current, NULL);
- release_segments(mm);
- kmem_cache_free(mm_cachep, mm);
-
-fail_nomem:
- return retval;
+ current->mm = mm;
+ current->active_mm = mm;
+ activate_mm(active_mm, mm);
+ mm_release();
+ if (old_mm) {
+ if (active_mm != old_mm) BUG();
+ mmput(old_mm);
+ return 0;
+ }
+ mmdrop(active_mm);
+ return 0;
+ }
+ return -ENOMEM;
}
/*
@@ -468,9 +415,9 @@ static inline void flush_old_files(struct files_struct * files)
unsigned long set, i;
i = j * __NFDBITS;
- if (i >= files->max_fds)
+ if (i >= files->max_fds || i >= files->max_fdset)
break;
- set = xchg(&files->close_on_exec.fds_bits[j], 0);
+ set = xchg(&files->close_on_exec->fds_bits[j], 0);
j++;
for ( ; set ; i++,set >>= 1) {
if (set & 1)
@@ -632,7 +579,7 @@ int prepare_binprm(struct linux_binprm *bprm)
if (id_change || cap_raised) {
/* 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) */
- /* (current->mm->count > 1 is ok, as we'll get a new mm anyway) */
+ /* (current->mm->mm_users > 1 is ok, as we'll get a new mm anyway) */
if (IS_NOSUID(inode)
|| must_not_trace_exec(current)
|| (atomic_read(&current->fs->count) > 1)
@@ -850,3 +797,54 @@ out:
return retval;
}
+
+int do_coredump(long signr, struct pt_regs * regs)
+{
+ struct linux_binfmt * binfmt;
+ char corename[6+sizeof(current->comm)];
+ struct file * file;
+ struct dentry * dentry;
+ struct inode * inode;
+
+ lock_kernel();
+ binfmt = current->binfmt;
+ if (!binfmt || !binfmt->core_dump)
+ goto fail;
+ if (!current->dumpable || atomic_read(&current->mm->mm_users) != 1)
+ goto fail;
+ current->dumpable = 0;
+ if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
+ goto fail;
+
+ memcpy(corename,"core.", 5);
+#if 0
+ memcpy(corename+5,current->comm,sizeof(current->comm));
+#else
+ corename[4] = '\0';
+#endif
+ file = filp_open(corename, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
+ if (IS_ERR(file))
+ goto fail;
+ dentry = file->f_dentry;
+ inode = dentry->d_inode;
+ if (inode->i_nlink > 1)
+ goto close_fail; /* multiple links - don't dump */
+
+ if (!S_ISREG(inode->i_mode))
+ goto close_fail;
+ if (!inode->i_op || !inode->i_op->default_file_ops)
+ goto close_fail;
+ if (!file->f_op->write)
+ goto close_fail;
+ if (!binfmt->core_dump(signr, regs, file))
+ goto close_fail;
+ filp_close(file, NULL);
+ unlock_kernel();
+ return 1;
+
+close_fail:
+ filp_close(file, NULL);
+fail:
+ unlock_kernel();
+ return 0;
+}
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 053022309..b7cfd2212 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -368,11 +368,10 @@ int ext2_new_block (const struct inode * inode, unsigned long goal,
struct super_block * sb;
struct ext2_group_desc * gdp;
struct ext2_super_block * es;
-
- *err = -ENOSPC;
#ifdef EXT2FS_DEBUG
static int goal_hits = 0, goal_attempts = 0;
#endif
+ *err = -ENOSPC;
sb = inode->i_sb;
if (!sb) {
printk ("ext2_new_block: nonexistent device");
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index f6a5ecfc6..d4b5ca33f 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -200,7 +200,7 @@ void ext2_free_inode (struct inode * inode)
}
if (inode->i_nlink) {
printk ("ext2_free_inode: inode has nlink=%d\n",
- (int) inode->i_nlink);
+ inode->i_nlink);
return;
}
if (!sb) {
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 171f34a16..52e97c585 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -259,20 +259,22 @@ repeat:
}
if (metadata) {
result = getblk (inode->i_dev, tmp, blocksize);
+ memset(result->b_data, 0, blocksize);
+ mark_buffer_uptodate(result, 1);
+ mark_buffer_dirty(result, 1);
if (*p) {
ext2_free_blocks (inode, tmp, 1);
- brelse (result);
+ bforget (result);
goto repeat;
}
- memset(result->b_data, 0, blocksize);
- mark_buffer_uptodate(result, 1);
- mark_buffer_dirty(result, 1);
} else {
if (*p) {
/*
* Nobody is allowed to change block allocation
* state from under us:
*/
+ ext2_error (inode->i_sb, "block_getblk",
+ "data block filled under us");
BUG();
ext2_free_blocks (inode, tmp, 1);
goto repeat;
@@ -366,23 +368,29 @@ repeat:
goto out;
if (metadata) {
result = getblk (bh->b_dev, tmp, blocksize);
+ memset(result->b_data, 0, inode->i_sb->s_blocksize);
+ mark_buffer_uptodate(result, 1);
+ mark_buffer_dirty(result, 1);
if (*p) {
ext2_free_blocks (inode, tmp, 1);
- brelse (result);
+ bforget (result);
goto repeat;
}
- memset(result->b_data, 0, inode->i_sb->s_blocksize);
- mark_buffer_uptodate(result, 1);
- mark_buffer_dirty(result, 1);
} else {
+ if (*p) {
+ /*
+ * Nobody is allowed to change block allocation
+ * state from under us:
+ */
+ ext2_error (inode->i_sb, "block_getblk",
+ "data block filled under us");
+ BUG();
+ ext2_free_blocks (inode, tmp, 1);
+ goto repeat;
+ }
*phys = tmp;
*new = 1;
}
- if (*p) {
- ext2_free_blocks (inode, tmp, 1);
- brelse (result);
- goto repeat;
- }
*p = le32_to_cpu(tmp);
mark_buffer_dirty(bh, 1);
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
@@ -848,10 +856,11 @@ int ext2_notify_change(struct dentry *dentry, struct iattr *iattr)
unsigned int flags;
retval = -EPERM;
- if ((iattr->ia_attr_flags &
- (ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^
- (inode->u.ext2_i.i_flags &
- (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
+ if (iattr->ia_valid & ATTR_ATTR_FLAG &&
+ ((!(iattr->ia_attr_flags & ATTR_FLAG_APPEND) !=
+ !(inode->u.ext2_i.i_flags & EXT2_APPEND_FL)) ||
+ (!(iattr->ia_attr_flags & ATTR_FLAG_IMMUTABLE) !=
+ !(inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL)))) {
if (!capable(CAP_LINUX_IMMUTABLE))
goto out;
} else if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 9666118ee..90cb80050 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -618,7 +618,7 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
if (inode->i_nlink != 2)
ext2_warning (inode->i_sb, "ext2_rmdir",
"empty directory has nlink!=2 (%d)",
- (int) inode->i_nlink);
+ inode->i_nlink);
inode->i_version = ++event;
inode->i_nlink = 0;
inode->i_size = 0;
@@ -656,7 +656,7 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry)
if (!inode->i_nlink) {
ext2_warning (inode->i_sb, "ext2_unlink",
"Deleting nonexistent file (%lu), %d",
- inode->i_ino, (int) inode->i_nlink);
+ inode->i_ino, inode->i_nlink);
inode->i_nlink = 1;
}
retval = ext2_delete_entry (de, bh);
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 758da8ff0..37b8e15c5 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -739,7 +739,7 @@ static struct file_system_type ext2_fs_type = {
NULL
};
-__initfunc(int init_ext2_fs(void))
+int __init init_ext2_fs(void)
{
return register_filesystem(&ext2_fs_type);
}
diff --git a/fs/fat/buffer.c b/fs/fat/buffer.c
index 4460e94d8..7ab13267d 100644
--- a/fs/fat/buffer.c
+++ b/fs/fat/buffer.c
@@ -17,195 +17,189 @@
# define PRINTK(x)
#endif
-struct buffer_head *fat_bread (
+struct buffer_head *fat_bread(struct super_block *sb, int block)
+{
+ return MSDOS_SB(sb)->cvf_format->cvf_bread(sb,block);
+}
+struct buffer_head *fat_getblk(struct super_block *sb, int block)
+{
+ return MSDOS_SB(sb)->cvf_format->cvf_getblk(sb,block);
+}
+void fat_brelse (struct super_block *sb, struct buffer_head *bh)
+{
+ if (bh)
+ MSDOS_SB(sb)->cvf_format->cvf_brelse(sb,bh);
+}
+void fat_mark_buffer_dirty (
struct super_block *sb,
- int block)
+ struct buffer_head *bh,
+ int dirty)
{
- struct buffer_head *ret = NULL;
-
- PRINTK(("fat_bread: block=0x%x\n", block));
- /*
- * Note that the blocksize is 512, 1024 or 2048, but the first read
- * is always of size 1024 (or 2048). Doing readahead may be
- * counterproductive or just plain wrong.
- */
+ MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty);
+}
+void fat_set_uptodate (
+ struct super_block *sb,
+ struct buffer_head *bh,
+ int val)
+{
+ MSDOS_SB(sb)->cvf_format->cvf_set_uptodate(sb,bh,val);
+}
+int fat_is_uptodate(struct super_block *sb, struct buffer_head *bh)
+{
+ return MSDOS_SB(sb)->cvf_format->cvf_is_uptodate(sb,bh);
+}
+void fat_ll_rw_block (
+ struct super_block *sb,
+ int opr,
+ int nbreq,
+ struct buffer_head *bh[32])
+{
+ MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block(sb,opr,nbreq,bh);
+}
- if(MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_bread)
- return MSDOS_SB(sb)->cvf_format->cvf_bread(sb,block);
+struct buffer_head *default_fat_bread(struct super_block *sb, int block)
+{
+ return bread (sb->s_dev,block,512);
+}
+struct buffer_head *default_fat_getblk(struct super_block *sb, int block)
+{
+ return getblk (sb->s_dev,block,512);
+}
+void default_fat_brelse(struct super_block *sb, struct buffer_head *bh)
+{
+ brelse (bh);
+}
+void default_fat_mark_buffer_dirty (
+ struct super_block *sb,
+ struct buffer_head *bh,
+ int dirty)
+{
+ mark_buffer_dirty (bh,dirty);
+}
+void default_fat_set_uptodate (
+ struct super_block *sb,
+ struct buffer_head *bh,
+ int val)
+{
+ mark_buffer_uptodate(bh, val);
+}
+int default_fat_is_uptodate (struct super_block *sb, struct buffer_head *bh)
+{
+ return buffer_uptodate(bh);
+}
+void default_fat_ll_rw_block (
+ struct super_block *sb,
+ int opr,
+ int nbreq,
+ struct buffer_head *bh[32])
+{
+ ll_rw_block(opr,nbreq,bh);
+}
- if (sb->s_blocksize == 512) {
- ret = bread (sb->s_dev,block,512);
+struct buffer_head *bigblock_fat_bread (
+ struct super_block *sb,
+ int block)
+{
+ struct buffer_head *ret = NULL;
+ struct buffer_head *real;
+ if (sb->s_blocksize == 1024){
+ real = bread (sb->s_dev,block>>1,1024);
} else {
- struct buffer_head *real;
- if (sb->s_blocksize == 1024){
- real = bread (sb->s_dev,block>>1,1024);
- } else {
- real = bread (sb->s_dev,block>>2,2048);
- }
-
- if (real != NULL){
- ret = (struct buffer_head *)
- kmalloc (sizeof(struct buffer_head), GFP_KERNEL);
- if (ret != NULL) {
- /* #Specification: msdos / strategy / special device / dummy blocks
- * Many special device (Scsi optical disk for one) use
- * larger hardware sector size. This allows for higher
- * capacity.
-
- * Most of the time, the MS-DOS filesystem that sits
- * on this device is totally unaligned. It use logically
- * 512 bytes sector size, with logical sector starting
- * in the middle of a hardware block. The bad news is
- * that a hardware sector may hold data own by two
- * different files. This means that the hardware sector
- * must be read, patch and written almost all the time.
-
- * Needless to say that it kills write performance
- * on all OS.
-
- * Internally the linux msdos fs is using 512 bytes
- * logical sector. When accessing such a device, we
- * allocate dummy buffer cache blocks, that we stuff
- * with the information of a real one (1k large).
+ real = bread (sb->s_dev,block>>2,2048);
+ }
- * This strategy is used to hide this difference to
- * the core of the msdos fs. The slowdown is not
- * hidden though!
- */
- /*
- * The memset is there only to catch errors. The msdos
- * fs is only using b_data
- */
- memset (ret,0,sizeof(*ret));
- ret->b_data = real->b_data;
- if (sb->s_blocksize == 2048) {
- if (block & 3) ret->b_data += (block & 3) << 9;
- }else{
- if (block & 1) ret->b_data += 512;
- }
- ret->b_next = real;
+ if (real != NULL) {
+ ret = (struct buffer_head *)
+ kmalloc (sizeof(struct buffer_head), GFP_KERNEL);
+ if (ret != NULL) {
+ /* #Specification: msdos / strategy / special device / dummy blocks
+ * Many special device (Scsi optical disk for one) use
+ * larger hardware sector size. This allows for higher
+ * capacity.
+
+ * Most of the time, the MS-DOS filesystem that sits
+ * on this device is totally unaligned. It use logically
+ * 512 bytes sector size, with logical sector starting
+ * in the middle of a hardware block. The bad news is
+ * that a hardware sector may hold data own by two
+ * different files. This means that the hardware sector
+ * must be read, patch and written almost all the time.
+
+ * Needless to say that it kills write performance
+ * on all OS.
+
+ * Internally the linux msdos fs is using 512 bytes
+ * logical sector. When accessing such a device, we
+ * allocate dummy buffer cache blocks, that we stuff
+ * with the information of a real one (1k large).
+
+ * This strategy is used to hide this difference to
+ * the core of the msdos fs. The slowdown is not
+ * hidden though!
+ */
+ /*
+ * The memset is there only to catch errors. The msdos
+ * fs is only using b_data
+ */
+ memset (ret,0,sizeof(*ret));
+ ret->b_data = real->b_data;
+ if (sb->s_blocksize == 2048) {
+ if (block & 3) ret->b_data += (block & 3) << 9;
}else{
- brelse (real);
+ if (block & 1) ret->b_data += 512;
}
+ ret->b_next = real;
+ }else{
+ brelse (real);
}
}
return ret;
}
-struct buffer_head *fat_getblk(struct super_block *sb, int block)
-{
- struct buffer_head *ret = NULL;
- PRINTK(("fat_getblk: block=0x%x\n", block));
-
- if (MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_getblk)
- return MSDOS_SB(sb)->cvf_format->cvf_getblk(sb,block);
-
- if (sb->s_blocksize == 512){
- ret = getblk (sb->s_dev,block,512);
- } else {
- /*
- * #Specification: msdos / special device / writing
- * A write is always preceded by a read of the complete block
- * (large hardware sector size). This defeat write performance.
- * There is a possibility to optimize this when writing large
- * chunk by making sure we are filling large block. Volunteer ?
- */
- ret = fat_bread (sb,block);
- }
- return ret;
-}
-
-void fat_brelse (
+void bigblock_fat_brelse (
struct super_block *sb,
struct buffer_head *bh)
{
- if (bh != NULL) {
- if (MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_brelse)
- return MSDOS_SB(sb)->cvf_format->cvf_brelse(sb,bh);
-
- if (sb->s_blocksize == 512){
- brelse (bh);
- }else{
- brelse (bh->b_next);
- /* We can free the dummy because a new one is allocated at
- each fat_getblk() and fat_bread().
- */
- kfree (bh);
- }
- }
+ brelse (bh->b_next);
+ /*
+ * We can free the dummy because a new one is allocated at
+ * each fat_getblk() and fat_bread().
+ */
+ kfree (bh);
}
-
-void fat_mark_buffer_dirty (
+
+void bigblock_fat_mark_buffer_dirty (
struct super_block *sb,
struct buffer_head *bh,
int dirty)
{
- if (MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty) {
- MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty);
- return;
- }
-
- if (sb->s_blocksize != 512){
- bh = bh->b_next;
- }
- mark_buffer_dirty (bh,dirty);
+ mark_buffer_dirty (bh->b_next,dirty);
}
-void fat_set_uptodate (
+void bigblock_fat_set_uptodate (
struct super_block *sb,
struct buffer_head *bh,
int val)
{
- if (MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_set_uptodate) {
- MSDOS_SB(sb)->cvf_format->cvf_set_uptodate(sb,bh,val);
- return;
- }
-
- if (sb->s_blocksize != 512){
- bh = bh->b_next;
- }
- mark_buffer_uptodate(bh, val);
+ mark_buffer_uptodate(bh->b_next, val);
}
-int fat_is_uptodate (
+
+int bigblock_fat_is_uptodate (
struct super_block *sb,
struct buffer_head *bh)
{
- if(MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_is_uptodate)
- return MSDOS_SB(sb)->cvf_format->cvf_is_uptodate(sb,bh);
-
- if (sb->s_blocksize != 512){
- bh = bh->b_next;
- }
- return buffer_uptodate(bh);
+ return buffer_uptodate(bh->b_next);
}
-void fat_ll_rw_block (
+void bigblock_fat_ll_rw_block (
struct super_block *sb,
int opr,
int nbreq,
struct buffer_head *bh[32])
{
- if (MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block) {
- MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block(sb,opr,nbreq,bh);
- return;
- }
-
- if (sb->s_blocksize == 512){
- ll_rw_block(opr,nbreq,bh);
- }else{
- struct buffer_head *tmp[32];
- int i;
- for (i=0; i<nbreq; i++){
- tmp[i] = bh[i]->b_next;
- }
- ll_rw_block(opr,nbreq,tmp);
- }
+ struct buffer_head *tmp[32];
+ int i;
+ for (i=0; i<nbreq; i++)
+ tmp[i] = bh[i]->b_next;
+ ll_rw_block(opr,nbreq,tmp);
}
-
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index b984fe759..45f4a800c 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -30,14 +30,20 @@ static struct fat_cache *fat_cache,cache[FAT_CACHE];
int fat_access(struct super_block *sb,int nr,int new_value)
{
+ return MSDOS_SB(sb)->cvf_format->fat_access(sb,nr,new_value);
+}
+
+int fat_bmap(struct inode *inode,int sector)
+{
+ return MSDOS_SB(inode->i_sb)->cvf_format->cvf_bmap(inode,sector);
+}
+
+int default_fat_access(struct super_block *sb,int nr,int new_value)
+{
struct buffer_head *bh,*bh2,*c_bh,*c_bh2;
unsigned char *p_first,*p_last;
int copy,first,last,next,b;
- if (MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->fat_access)
- return MSDOS_SB(sb)->cvf_format->fat_access(sb,nr,new_value);
-
if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters)
return 0;
if (MSDOS_SB(sb)->fat_bits == 32) {
@@ -265,14 +271,11 @@ int fat_get_cluster(struct inode *inode,int cluster)
return nr;
}
-int fat_smap(struct inode *inode,int sector)
+int default_fat_bmap(struct inode *inode,int sector)
{
- struct msdos_sb_info *sb;
+ struct msdos_sb_info *sb=MSDOS_SB(inode->i_sb);
int cluster,offset;
- sb = MSDOS_SB(inode->i_sb);
- if (sb->cvf_format && sb->cvf_format->cvf_smap)
- return sb->cvf_format->cvf_smap(inode,sector);
if ((sb->fat_bits != 32) &&
(inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
!MSDOS_I(inode)->i_start))) {
@@ -280,6 +283,8 @@ int fat_smap(struct inode *inode,int sector)
return 0;
return sector+sb->dir_start;
}
+ if (sector >= (MSDOS_I(inode)->i_realsize>>9))
+ return 0;
cluster = sector/sb->cluster_size;
offset = sector % sb->cluster_size;
if (!(cluster = fat_get_cluster(inode,cluster))) return 0;
diff --git a/fs/fat/cvf.c b/fs/fat/cvf.c
index 9dd70f8c5..24cf1164f 100644
--- a/fs/fat/cvf.c
+++ b/fs/fat/cvf.c
@@ -21,6 +21,83 @@
#define MAX_CVF_FORMATS 3
+struct buffer_head *default_fat_bread(struct super_block *,int);
+struct buffer_head *default_fat_getblk(struct super_block *, int);
+struct buffer_head *bigblock_fat_bread(struct super_block *, int);
+void default_fat_brelse(struct super_block *, struct buffer_head *);
+void bigblock_fat_brelse(struct super_block *, struct buffer_head *);
+void default_fat_mark_buffer_dirty (struct super_block *,
+ struct buffer_head *, int);
+void bigblock_fat_mark_buffer_dirty (struct super_block *,
+ struct buffer_head *, int);
+void default_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
+void bigblock_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
+int default_fat_is_uptodate(struct super_block *, struct buffer_head *);
+int bigblock_fat_is_uptodate(struct super_block *, struct buffer_head *);
+int default_fat_access(struct super_block *sb,int nr,int new_value);
+void default_fat_ll_rw_block (
+ struct super_block *sb,
+ int opr,
+ int nbreq,
+ struct buffer_head *bh[32]);
+void bigblock_fat_ll_rw_block (
+ struct super_block *sb,
+ int opr,
+ int nbreq,
+ struct buffer_head *bh[32]);
+int default_fat_bmap(struct inode *inode,int block);
+ssize_t default_fat_file_write(
+ struct file *filp,
+ const char *buf,
+ size_t count,
+ loff_t *ppos);
+
+struct cvf_format default_cvf = {
+ 0, /* version - who cares? */
+ "plain",
+ 0, /* flags - who cares? */
+ NULL,
+ NULL,
+ NULL,
+ default_fat_bread,
+ default_fat_getblk,
+ default_fat_brelse,
+ default_fat_mark_buffer_dirty,
+ default_fat_set_uptodate,
+ default_fat_is_uptodate,
+ default_fat_ll_rw_block,
+ default_fat_access,
+ NULL,
+ default_fat_bmap,
+ generic_file_read,
+ default_fat_file_write,
+ NULL,
+ NULL
+};
+
+struct cvf_format bigblock_cvf = {
+ 0, /* version - who cares? */
+ "big_blocks",
+ 0, /* flags - who cares? */
+ NULL,
+ NULL,
+ NULL,
+ bigblock_fat_bread,
+ bigblock_fat_bread,
+ bigblock_fat_brelse,
+ bigblock_fat_mark_buffer_dirty,
+ bigblock_fat_set_uptodate,
+ bigblock_fat_is_uptodate,
+ bigblock_fat_ll_rw_block,
+ default_fat_access,
+ NULL,
+ default_fat_bmap,
+ NULL,
+ default_fat_file_write,
+ NULL,
+ NULL
+};
+
struct cvf_format *cvf_formats[MAX_CVF_FORMATS]={NULL,NULL,NULL};
int cvf_format_use_count[MAX_CVF_FORMATS]={0,0,0};
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 82d29a0df..628c0bb9c 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -605,7 +605,7 @@ int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
struct super_block *sb = dir->i_sb;
loff_t offset, curr;
int row;
- int res;
+ struct buffer_head *new_bh;
offset = curr = 0;
*bh = NULL;
@@ -621,11 +621,47 @@ int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
}
if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32))
return -ENOSPC;
- if ((res = fat_add_cluster(dir)) < 0) return res;
+ new_bh = fat_extend_dir(dir);
+ if (!new_bh)
+ return -ENOSPC;
+ fat_brelse(sb, new_bh);
do fat_get_entry(dir,&curr,bh,de,ino); while (++row<slots);
return offset;
}
+int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat)
+{
+ struct super_block *sb = dir->i_sb;
+ struct buffer_head *bh;
+ struct msdos_dir_entry *de;
+ __u16 date, time;
+
+ if ((bh = fat_extend_dir(dir)) == NULL) return -ENOSPC;
+ /* zeroed out, so... */
+ fat_date_unix2dos(dir->i_mtime,&time,&date);
+ de = (struct msdos_dir_entry*)&bh->b_data[0];
+ memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);
+ memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);
+ de[0].attr = de[1].attr = ATTR_DIR;
+ de[0].time = de[1].time = CT_LE_W(time);
+ de[0].date = de[1].date = CT_LE_W(date);
+ if (is_vfat) { /* extra timestamps */
+ de[0].ctime = de[1].ctime = CT_LE_W(time);
+ de[0].adate = de[0].cdate =
+ de[1].adate = de[1].cdate = CT_LE_W(date);
+ }
+ de[0].start = CT_LE_W(MSDOS_I(dir)->i_logstart);
+ de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16);
+ de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart);
+ de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16);
+ fat_mark_buffer_dirty(sb, bh, 1);
+ fat_brelse(sb, bh);
+ dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(dir);
+
+ return 0;
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/fs/fat/fatfs_syms.c b/fs/fat/fatfs_syms.c
index a8cd88cac..070361aa9 100644
--- a/fs/fat/fatfs_syms.c
+++ b/fs/fat/fatfs_syms.c
@@ -17,9 +17,9 @@
extern struct file_operations fat_dir_operations;
-EXPORT_SYMBOL(fat_add_cluster);
-EXPORT_SYMBOL(fat_add_cluster1);
+EXPORT_SYMBOL(fat_new_dir);
EXPORT_SYMBOL(fat_bmap);
+EXPORT_SYMBOL(fat_get_block);
EXPORT_SYMBOL(fat_brelse);
EXPORT_SYMBOL(fat_cache_inval_inode);
EXPORT_SYMBOL(fat_clear_inode);
@@ -44,9 +44,7 @@ EXPORT_SYMBOL(fat_read_super);
EXPORT_SYMBOL(fat_search_long);
EXPORT_SYMBOL(fat_readdir);
EXPORT_SYMBOL(fat_scan);
-EXPORT_SYMBOL(fat_smap);
EXPORT_SYMBOL(fat_statfs);
-EXPORT_SYMBOL(fat_truncate);
EXPORT_SYMBOL(fat_uni2esc);
EXPORT_SYMBOL(fat_unlock_creation);
EXPORT_SYMBOL(fat_write_inode);
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 5d964da2b..19b91b74f 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -57,7 +57,7 @@ struct inode_operations fat_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- fat_bmap, /* get_block */
+ fat_get_block, /* get_block */
block_read_full_page, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -67,392 +67,117 @@ struct inode_operations fat_file_inode_operations = {
NULL /* revalidate */
};
-/* #Specification: msdos / special devices / mmap
- Mmapping does work because a special mmap is provide in that case.
- Note that it is much less efficient than the generic_file_mmap normally
- used since it allocate extra buffer. generic_file_mmap is used for
- normal device (512 bytes hardware sectors).
-*/
-static struct file_operations fat_file_operations_1024 = {
- NULL, /* lseek - default */
- fat_file_read, /* read */
- fat_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* select v2.0.x/poll v2.1.x - default */
- NULL, /* ioctl - default */
- fat_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- NULL, /* release */
- file_fsync /* fsync */
-};
-
-/* #Specification: msdos / special devices / swap file
- Swap file can't work on special devices with a large sector
- size (1024 bytes hard sector). Those devices have a weird
- MS-DOS filesystem layout. Generally a single hardware sector
- may contain 2 unrelated logical sector. This mean that there is
- no easy way to do a mapping between disk sector of a file and virtual
- memory. So swap file is difficult (not available right now)
- on those devices. Off course, Ext2 does not have this problem.
-*/
-struct inode_operations fat_file_inode_operations_1024 = {
- &fat_file_operations_1024, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- block_read_full_page, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- fat_truncate, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-static struct file_operations fat_file_operations_readpage = {
- NULL, /* lseek - default */
- fat_file_read, /* read */
- fat_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* select v2.0.x/poll v2.1.x - default */
- NULL, /* ioctl - default */
- generic_file_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- NULL, /* release */
- file_fsync /* fsync */
-};
-
-struct inode_operations fat_file_inode_operations_readpage = {
- &fat_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 */
- NULL, /* get_block */
- fat_readpage, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- fat_truncate, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-#define MSDOS_PREFETCH 32
-struct fat_pre {
- int file_sector;/* Next sector to read in the prefetch table */
- /* This is relative to the file, not the disk */
- struct buffer_head *bhlist[MSDOS_PREFETCH]; /* All buffers needed */
- int nblist; /* Number of buffers in bhlist */
- int nolist; /* index in bhlist */
-};
-/*
- Order the prefetch of more sectors.
-*/
-static void fat_prefetch (
- struct inode *inode,
- struct fat_pre *pre,
- int nb) /* How many must we prefetch at once */
-{
- struct super_block *sb = inode->i_sb;
- struct buffer_head *bhreq[MSDOS_PREFETCH]; /* Buffers not */
- /* already read */
- int nbreq = 0; /* Number of buffers in bhreq */
- int i;
- for (i=0; i<nb; i++){
- int sector = fat_smap(inode,pre->file_sector);
- if (sector != 0){
- struct buffer_head *bh;
- PRINTK (("fsector2 %d -> %d\n",pre->file_sector-1,sector));
- pre->file_sector++;
- bh = fat_getblk(sb, sector);
- if (bh == NULL) break;
- pre->bhlist[pre->nblist++] = bh;
- if (!fat_is_uptodate(sb,bh))
- bhreq[nbreq++] = bh;
- }else{
- break;
- }
- }
- if (nbreq > 0) fat_ll_rw_block (sb,READ,nbreq,bhreq);
- for (i=pre->nblist; i<MSDOS_PREFETCH; i++) pre->bhlist[i] = NULL;
-}
-
-/*
- Read a file into user space
-*/
-static ssize_t fat_file_read_text(
+ssize_t fat_file_read(
struct file *filp,
char *buf,
size_t count,
loff_t *ppos)
{
struct inode *inode = filp->f_dentry->d_inode;
- struct super_block *sb = inode->i_sb;
- char *start = buf;
- char *end = buf + count;
- int i;
- int left_in_file;
- struct fat_pre pre;
-
+ return MSDOS_SB(inode->i_sb)->cvf_format
+ ->cvf_file_read(filp,buf,count,ppos);
+}
- if (!inode) {
- printk("fat_file_read: inode = NULL\n");
- return -EINVAL;
+
+int fat_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create) {
+ unsigned long phys;
+ phys = fat_bmap(inode, iblock);
+ if (phys) {
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ return 0;
}
- /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
- if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
- printk("fat_file_read: mode = %07o\n",inode->i_mode);
- return -EINVAL;
+ if (!create)
+ return 0;
+ if (iblock<<9 != MSDOS_I(inode)->i_realsize) {
+ BUG();
+ return -EIO;
}
- if (*ppos >= inode->i_size || count == 0) return 0;
- /*
- Tell the buffer cache which block we expect to read in advance
- Since we are limited with the stack, we preread only MSDOS_PREFETCH
- because we have to keep the result into the local
- arrays pre.bhlist and bhreq.
-
- Each time we process one block in bhlist, we replace
- it by a new prefetch block if needed.
- */
- PRINTK (("#### ino %ld pos %ld size %ld count %d\n",inode->i_ino,*ppos,inode->i_size,count));
- {
- /*
- We must prefetch complete block, so we must
- take in account the offset in the first block.
- */
- int count_max = (*ppos & (SECTOR_SIZE-1)) + count;
- int to_reada; /* How many block to read all at once */
- pre.file_sector = *ppos >> SECTOR_BITS;
- to_reada = count_max / SECTOR_SIZE;
- if (count_max & (SECTOR_SIZE-1)) to_reada++;
- if (filp->f_reada || !MSDOS_I(inode)->i_binary){
- /* Doing a read ahead on ASCII file make sure we always */
- /* read enough, since we don't know how many blocks */
- /* we really need */
- int ahead = read_ahead[MAJOR(inode->i_dev)];
- PRINTK (("to_reada %d ahead %d\n",to_reada,ahead));
- if (ahead == 0) ahead = 8;
- to_reada += ahead;
- }
- if (to_reada > MSDOS_PREFETCH) to_reada = MSDOS_PREFETCH;
- pre.nblist = 0;
- fat_prefetch (inode,&pre,to_reada);
+ if (!(iblock % MSDOS_SB(inode->i_sb)->cluster_size)) {
+ if (fat_add_cluster(inode))
+ return -ENOSPC;
}
- pre.nolist = 0;
- PRINTK (("count %d ahead %d nblist %d\n",count,read_ahead[MAJOR(inode->i_dev)],pre.nblist));
- while ((left_in_file = inode->i_size - *ppos) > 0
- && buf < end){
- struct buffer_head *bh = pre.bhlist[pre.nolist];
- char *data;
- int size,offset;
- if (bh == NULL) break;
- pre.bhlist[pre.nolist] = NULL;
- pre.nolist++;
- if (pre.nolist == MSDOS_PREFETCH/2){
- memcpy (pre.bhlist,pre.bhlist+MSDOS_PREFETCH/2
- ,(MSDOS_PREFETCH/2)*sizeof(pre.bhlist[0]));
- pre.nblist -= MSDOS_PREFETCH/2;
- fat_prefetch (inode,&pre,MSDOS_PREFETCH/2);
- pre.nolist = 0;
- }
- PRINTK (("file_read pos %ld nblist %d %d %d\n",*ppos,pre.nblist,pre.fetched,count));
- wait_on_buffer(bh);
- if (!fat_is_uptodate(sb,bh)){
- /* read error ? */
- fat_brelse (sb, bh);
- break;
- }
- offset = *ppos & (SECTOR_SIZE-1);
- data = bh->b_data + offset;
- size = MIN(SECTOR_SIZE-offset,left_in_file);
- if (MSDOS_I(inode)->i_binary) {
- size = MIN(size,end-buf);
- copy_to_user(buf,data,size);
- buf += size;
- *ppos += size;
- }else{
- for (; size && buf < end; size--) {
- char ch = *data++;
- ++*ppos;
- if (ch == 26){
- *ppos = inode->i_size;
- break;
- }else if (ch != '\r'){
- put_user(ch,buf++);
- }
+ MSDOS_I(inode)->i_realsize+=SECTOR_SIZE;
+ phys=fat_bmap(inode, iblock);
+ if (!phys)
+ BUG();
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ bh_result->b_state |= (1UL << BH_New);
+ return 0;
+}
+
+static int fat_write_partial_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+{
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct page *new_page, **hash;
+ unsigned long pgpos;
+ unsigned long page_cache = 0;
+ long status;
+
+ pgpos = inode->i_size & PAGE_CACHE_MASK;
+ while (pgpos < page->offset) {
+ hash = page_hash(inode, pgpos);
+repeat_find: new_page = __find_lock_page(inode, pgpos, hash);
+ if (!new_page) {
+ if (!page_cache) {
+ page_cache = page_cache_alloc();
+ if (page_cache)
+ goto repeat_find;
+ status = -ENOMEM;
+ goto out;
}
+ new_page = page_cache_entry(page_cache);
+ if (add_to_page_cache_unique(new_page,inode,pgpos,hash))
+ goto repeat_find;
+ page_cache = 0;
}
- fat_brelse(sb, bh);
+ status = block_write_cont_page(file, new_page, PAGE_SIZE, 0, NULL);
+ UnlockPage(new_page);
+ page_cache_release(new_page);
+ if (status < 0)
+ goto out;
+ pgpos = MSDOS_I(inode)->i_realsize & PAGE_CACHE_MASK;
}
- PRINTK (("--- %d -> %d\n",count,(int)(buf-start)));
- for (i=0; i<pre.nblist; i++)
- fat_brelse (sb, pre.bhlist[i]);
- if (start == buf)
- return -EIO;
- if (!IS_RDONLY(inode))
- inode->i_atime = CURRENT_TIME;
- filp->f_reada = 1; /* Will be reset if a lseek is done */
- return buf-start;
+ status = block_write_cont_page(file, page, offset, bytes, buf);
+out:
+ if (page_cache)
+ page_cache_free(page_cache);
+ return status;
}
-ssize_t fat_file_read(
+ssize_t fat_file_write(
struct file *filp,
- char *buf,
+ const char *buf,
size_t count,
loff_t *ppos)
{
struct inode *inode = filp->f_dentry->d_inode;
- if (MSDOS_SB(inode->i_sb)->cvf_format &&
- MSDOS_SB(inode->i_sb)->cvf_format->cvf_file_read)
- return MSDOS_SB(inode->i_sb)->cvf_format
- ->cvf_file_read(filp,buf,count,ppos);
-
- /*
- * MS-DOS filesystems with a blocksize > 512 may have blocks
- * spread over several hardware sectors (unaligned), which
- * is not something the generic routines can (or would want
- * to) handle).
- */
- if (!MSDOS_I(inode)->i_binary || inode->i_sb->s_blocksize > 512)
- return fat_file_read_text(filp, buf, count, ppos);
- return generic_file_read(filp, buf, count, ppos);
+ struct super_block *sb = inode->i_sb;
+ return MSDOS_SB(sb)->cvf_format
+ ->cvf_file_write(filp,buf,count,ppos);
}
-/*
- Write to a file either from user space
-*/
-ssize_t fat_file_write(
+
+ssize_t default_fat_file_write(
struct file *filp,
const char *buf,
size_t count,
loff_t *ppos)
{
struct inode *inode = filp->f_dentry->d_inode;
- struct super_block *sb = inode->i_sb;
- int sector,offset,size,left,written;
- int error,carry;
- const char *start;
- char *to,ch;
- struct buffer_head *bh;
- int binary_mode = MSDOS_I(inode)->i_binary;
-
- PRINTK(("fat_file_write: dentry=%p, inode=%p, ino=%ld\n",
- filp->f_dentry, inode, inode->i_ino));
- if (!inode) {
- printk("fat_file_write: inode = NULL\n");
- return -EINVAL;
- }
- if (MSDOS_SB(sb)->cvf_format &&
- MSDOS_SB(sb)->cvf_format->cvf_file_write)
- return MSDOS_SB(sb)->cvf_format
- ->cvf_file_write(filp,buf,count,ppos);
-
- /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
- if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
- printk("fat_file_write: mode = %07o\n",inode->i_mode);
- return -EINVAL;
- }
- /* system files may be immutable */
- if (IS_IMMUTABLE(inode))
- return -EPERM;
-/*
- * ok, append may not work when many processes are writing at the same time
- * but so what. That way leads to madness anyway.
- */
- if (filp->f_flags & O_APPEND)
- *ppos = inode->i_size;
- if (count == 0)
- return 0;
- if (*ppos + count > 0x7FFFFFFFLL) {
- count = 0x7FFFFFFFLL-*ppos;
- if (!count)
- return -EFBIG;
+ int retval;
+
+ retval = generic_file_write(filp, buf, count, ppos,
+ fat_write_partial_page);
+ if (retval > 0) {
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+ mark_inode_dirty(inode);
}
-
- error = carry = 0;
- for (start = buf; count || carry; count -= size) {
- while (!(sector = fat_smap(inode,*ppos >> SECTOR_BITS)))
- if ((error = fat_add_cluster(inode)) < 0) break;
- if (error) {
- fat_truncate(inode);
- break;
- }
- offset = *ppos & (SECTOR_SIZE-1);
- size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
- if (binary_mode
- && offset == 0
- && (size == SECTOR_SIZE
- || *ppos + size >= inode->i_size)){
- /* No need to read the block first since we will */
- /* completely overwrite it */
- /* or at least write past the end of file */
- if (!(bh = fat_getblk(sb,sector))){
- error = -EIO;
- break;
- }
- } else if (!(bh = fat_bread(sb,sector))) {
- error = -EIO;
- break;
- }
- if (binary_mode) {
- copy_from_user(bh->b_data+offset,buf,written = size);
- buf += size;
- } else {
- written = left = SECTOR_SIZE-offset;
- to = (char *) bh->b_data+(*ppos & (SECTOR_SIZE-1));
- if (carry) {
- *to++ = '\n';
- left--;
- carry = 0;
- }
- for (size = 0; size < count && left; size++) {
- get_user(ch, buf++);
- if (ch == '\n') {
- *to++ = '\r';
- left--;
- }
- if (!left) carry = 1;
- else {
- *to++ = ch;
- left--;
- }
- }
- written -= left;
- }
- update_vm_cache(inode, *ppos, bh->b_data + (*ppos & (SECTOR_SIZE-1)), written);
- *ppos += written;
- if (*ppos > inode->i_size) {
- inode->i_size = *ppos;
- mark_inode_dirty(inode);
- }
- fat_set_uptodate(sb, bh, 1);
- fat_mark_buffer_dirty(sb, bh, 0);
- fat_brelse(sb, bh);
- }
- if (start == buf)
- return error;
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
- mark_inode_dirty(inode);
- return buf-start;
+ return retval;
}
void fat_truncate(struct inode *inode)
@@ -460,14 +185,14 @@ void fat_truncate(struct inode *inode)
int cluster;
/* Why no return value? Surely the disk could fail... */
+ if (IS_RDONLY (inode))
+ return /* -EPERM */;
if (IS_IMMUTABLE(inode))
return /* -EPERM */;
- if(inode->i_sb->s_flags&MS_RDONLY) {
- printk("FAT: fat_truncate called though fs is read-only, uhh...\n");
- return /* -EROFS */;
- }
cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
+ MSDOS_I(inode)->i_realsize = ((inode->i_size-1) | (SECTOR_SIZE-1)) + 1;
(void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
mark_inode_dirty(inode);
}
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index b55bfd712..4262fa756 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -33,6 +33,8 @@
#include <asm/uaccess.h>
#include <asm/unaligned.h>
+extern struct cvf_format default_cvf, bigblock_cvf;
+
/* #define FAT_PARANOIA 1 */
#define DEBUG_LEVEL 0
#ifdef FAT_DEBUG
@@ -166,7 +168,7 @@ void fat_clear_inode(struct inode *inode)
void fat_put_super(struct super_block *sb)
{
- if (MSDOS_SB(sb)->cvf_format) {
+ if (MSDOS_SB(sb)->cvf_format->cvf_version) {
dec_cvf_format_use_count_by_version(MSDOS_SB(sb)->cvf_format->cvf_version);
MSDOS_SB(sb)->cvf_format->unmount_cvf(sb);
}
@@ -305,12 +307,12 @@ static int parse_options(char *options,int *fat, int *blksize, int *debug,
else opts->quiet = 1;
}
else if (!strcmp(this_char,"blocksize")) {
- if (*value) ret = 0;
- else if (*blksize != 512 &&
- *blksize != 1024 &&
- *blksize != 2048) {
- printk ("MSDOS FS: Invalid blocksize "
- "(512, 1024, or 2048)\n");
+ if (!value || !*value) ret = 0;
+ else {
+ *blksize = simple_strtoul(value,&value,0);
+ if (*value || (*blksize != 512 &&
+ *blksize != 1024 && *blksize != 2048))
+ ret = 0;
}
}
else if (!strcmp(this_char,"sys_immutable")) {
@@ -364,7 +366,6 @@ static void fat_read_root(struct inode *inode)
struct super_block *sb = inode->i_sb;
int nr;
- MSDOS_I(inode)->i_binary = 1;
INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
MSDOS_I(inode)->i_location = 0;
MSDOS_I(inode)->i_fat_inode = inode;
@@ -394,6 +395,7 @@ static void fat_read_root(struct inode *inode)
inode->i_blocks = (inode->i_size+inode->i_blksize-1)/
inode->i_blksize*MSDOS_SB(sb)->cluster_size;
MSDOS_I(inode)->i_logstart = 0;
+ MSDOS_I(inode)->i_realsize = inode->i_size;
MSDOS_I(inode)->i_attrs = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
@@ -477,10 +479,10 @@ fat_read_super(struct super_block *sb, void *data, int silent,
sb->s_blocksize = 1024;
set_blocksize(sb->s_dev, 1024);
}
- bh = fat_bread(sb, 0);
+ bh = bread(sb->s_dev, 0, sb->s_blocksize);
unlock_super(sb);
- if (bh == NULL || !fat_is_uptodate(sb,bh)) {
- fat_brelse (sb, bh);
+ if (bh == NULL || !buffer_uptodate(bh)) {
+ brelse (bh);
goto out_no_bread;
}
@@ -514,7 +516,7 @@ fat_read_super(struct super_block *sb, void *data, int silent,
/* Must be FAT32 */
fat32 = 1;
- MSDOS_SB(sb)->fat_length= CF_LE_W(b->fat32_length)*sector_mult;
+ MSDOS_SB(sb)->fat_length= CF_LE_L(b->fat32_length)*sector_mult;
MSDOS_SB(sb)->root_cluster = CF_LE_L(b->root_cluster);
/* MC - if info_sector is 0, don't multiply by 0 */
@@ -572,7 +574,7 @@ fat_read_super(struct super_block *sb, void *data, int silent,
MSDOS_MAX_EXTRA || (logical_sector_size & (SECTOR_SIZE-1))
|| !b->secs_track || !b->heads;
}
- fat_brelse(sb, bh);
+ brelse(bh);
set_blocksize(sb->s_dev, blksize);
/*
This must be done after the brelse because the bh is a dummy
@@ -589,6 +591,10 @@ fat_read_super(struct super_block *sb, void *data, int silent,
i = detect_cvf(sb,cvf_format);
if (i >= 0)
error = cvf_formats[i]->mount_cvf(sb,cvf_options);
+ else if (sb->s_blocksize == 512)
+ MSDOS_SB(sb)->cvf_format = &default_cvf;
+ else
+ MSDOS_SB(sb)->cvf_format = &bigblock_cvf;
if (error || debug) {
/* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
@@ -616,7 +622,7 @@ fat_read_super(struct super_block *sb, void *data, int silent,
sb->s_magic = MSDOS_SUPER_MAGIC;
/* set up enough so that it can read an inode */
init_waitqueue_head(&MSDOS_SB(sb)->fat_wait);
- MSDOS_SB(sb)->fat_lock = 0;
+ init_MUTEX(&MSDOS_SB(sb)->fat_lock);
MSDOS_SB(sb)->prev_free = 0;
cp = opts.codepage ? opts.codepage : 437;
@@ -717,25 +723,6 @@ int fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
-
-int fat_bmap(struct inode *inode,int block)
-{
- struct msdos_sb_info *sb;
- int cluster,offset;
-
- sb = MSDOS_SB(inode->i_sb);
- if (sb->cvf_format &&
- sb->cvf_format->cvf_bmap)
- return sb->cvf_format->cvf_bmap(inode,block);
- if ((inode->i_ino == MSDOS_ROOT_INO) && (sb->fat_bits != 32)) {
- return sb->dir_start + block;
- }
- cluster = block/sb->cluster_size;
- offset = block % sb->cluster_size;
- if (!(cluster = fat_get_cluster(inode,cluster))) return 0;
- return (cluster-2)*sb->cluster_size+sb->data_start+offset;
-}
-
static int is_exec(char *extension)
{
char *exe_extensions = "EXECOMBAT", *walk;
@@ -752,7 +739,6 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
struct super_block *sb = inode->i_sb;
int nr;
- MSDOS_I(inode)->i_binary = 1;
INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
MSDOS_I(inode)->i_location = 0;
MSDOS_I(inode)->i_fat_inode = inode;
@@ -789,6 +775,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
break;
}
}
+ MSDOS_I(inode)->i_realsize = inode->i_size;
} else { /* not a directory */
inode->i_mode = MSDOS_MKMODE(de->attr,
((IS_NOEXEC(inode) ||
@@ -796,14 +783,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
!is_exec(de->ext)))
? S_IRUGO|S_IWUGO : S_IRWXUGO)
& ~MSDOS_SB(sb)->options.fs_umask) | S_IFREG;
- if (MSDOS_SB(sb)->cvf_format)
- inode->i_op = (MSDOS_SB(sb)->cvf_format->flags & CVF_USE_READPAGE)
- ? &fat_file_inode_operations_readpage
- : &fat_file_inode_operations_1024;
- else
- inode->i_op = (sb->s_blocksize == 1024 || sb->s_blocksize == 2048)
- ? &fat_file_inode_operations_1024
- : &fat_file_inode_operations;
+ inode->i_op = &fat_file_inode_operations;
MSDOS_I(inode)->i_start = CF_LE_W(de->start);
if (MSDOS_SB(sb)->fat_bits == 32) {
MSDOS_I(inode)->i_start |=
@@ -812,12 +792,11 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
inode->i_nlink = 1;
inode->i_size = CF_LE_L(de->size);
+ MSDOS_I(inode)->i_realsize = ((inode->i_size-1)|(SECTOR_SIZE-1))+1;
}
if(de->attr & ATTR_SYS)
if (MSDOS_SB(sb)->options.sys_immutable)
inode->i_flags |= S_IMMUTABLE;
- MSDOS_I(inode)->i_binary =
- fat_is_binary(MSDOS_SB(sb)->options.conversion, de->ext);
MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
/* this is as close to the truth as we can get ... */
inode->i_blksize = MSDOS_SB(sb)->cluster_size*SECTOR_SIZE;
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 4cd218d58..cd2762732 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -79,35 +79,29 @@ int fat_is_binary(char conversion,char *extension)
/* File creation lock. This is system-wide to avoid deadlocks in rename. */
/* (rename might deadlock before detecting cross-FS moves.) */
-static DECLARE_WAIT_QUEUE_HEAD(creation_wait);
-static int creation_lock = 0;
-
+static DECLARE_MUTEX(creation_lock);
void fat_lock_creation(void)
{
- while (creation_lock) sleep_on(&creation_wait);
- creation_lock = 1;
+ down(&creation_lock);
}
void fat_unlock_creation(void)
{
- creation_lock = 0;
- wake_up(&creation_wait);
+ up(&creation_lock);
}
void lock_fat(struct super_block *sb)
{
- while (MSDOS_SB(sb)->fat_lock) sleep_on(&MSDOS_SB(sb)->fat_wait);
- MSDOS_SB(sb)->fat_lock = 1;
+ down(&(MSDOS_SB(sb)->fat_lock));
}
void unlock_fat(struct super_block *sb)
{
- MSDOS_SB(sb)->fat_lock = 0;
- wake_up(&MSDOS_SB(sb)->fat_wait);
+ up(&(MSDOS_SB(sb)->fat_lock));
}
/* Flushes the number of free clusters on FAT32 */
@@ -144,7 +138,70 @@ void fat_clusters_flush(struct super_block *sb)
* represented by inode. The cluster is zero-initialized.
*/
-struct buffer_head *fat_add_cluster1(struct inode *inode)
+/* not a directory */
+
+int fat_add_cluster(struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+ int count,nr,limit,last,curr,file_cluster;
+ int res = -ENOSPC;
+ int cluster_size = MSDOS_SB(sb)->cluster_size;
+
+ if (!MSDOS_SB(sb)->free_clusters) return res;
+ lock_fat(sb);
+ limit = MSDOS_SB(sb)->clusters;
+ nr = limit; /* to keep GCC happy */
+ for (count = 0; count < limit; count++) {
+ nr = ((count+MSDOS_SB(sb)->prev_free) % limit)+2;
+ if (fat_access(sb,nr,-1) == 0) break;
+ }
+ MSDOS_SB(sb)->prev_free = (count+MSDOS_SB(sb)->prev_free+1) % limit;
+ if (count >= limit) {
+ MSDOS_SB(sb)->free_clusters = 0;
+ unlock_fat(sb);
+ return res;
+ }
+ fat_access(sb,nr,EOF_FAT(sb));
+ if (MSDOS_SB(sb)->free_clusters != -1)
+ MSDOS_SB(sb)->free_clusters--;
+ if (MSDOS_SB(sb)->fat_bits == 32)
+ fat_clusters_flush(sb);
+ unlock_fat(sb);
+ last = 0;
+ /* We must locate the last cluster of the file to add this
+ new one (nr) to the end of the link list (the FAT).
+
+ Here file_cluster will be the number of the last cluster of the
+ file (before we add nr).
+
+ last is the corresponding cluster number on the disk. We will
+ use last to plug the nr cluster. We will use file_cluster to
+ update the cache.
+ */
+ file_cluster = 0;
+ if ((curr = MSDOS_I(inode)->i_start) != 0) {
+ fat_cache_lookup(inode,INT_MAX,&last,&curr);
+ file_cluster = last;
+ while (curr && curr != -1){
+ file_cluster++;
+ if (!(curr = fat_access(sb, last = curr,-1))) {
+ fat_fs_panic(sb,"File without EOF");
+ return res;
+ }
+ }
+ }
+ if (last) fat_access(sb,last,nr);
+ else {
+ MSDOS_I(inode)->i_start = nr;
+ MSDOS_I(inode)->i_logstart = nr;
+ mark_inode_dirty(inode);
+ }
+ fat_cache_add(inode,file_cluster,nr);
+ inode->i_blocks += cluster_size;
+ return 0;
+}
+
+struct buffer_head *fat_extend_dir(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
int count,nr,limit,last,curr,sector,last_sector,file_cluster;
@@ -248,30 +305,17 @@ if (last) printk("next set to %d\n",fat_access(sb,last,-1));
fat_cache_add(inode,file_cluster,nr);
}
inode->i_blocks += cluster_size;
- if (S_ISDIR(inode->i_mode)) {
- if (inode->i_size & (SECTOR_SIZE-1)) {
- fat_fs_panic(sb,"Odd directory size");
- inode->i_size = (inode->i_size+SECTOR_SIZE) &
- ~(SECTOR_SIZE-1);
- }
- inode->i_size += SECTOR_SIZE*cluster_size;
-#ifdef DEBUG
-printk("size is %d now (%x)\n",inode->i_size,inode);
-#endif
- mark_inode_dirty(inode);
+ if (inode->i_size & (SECTOR_SIZE-1)) {
+ fat_fs_panic(sb,"Odd directory size");
+ inode->i_size = (inode->i_size+SECTOR_SIZE) &
+ ~(SECTOR_SIZE-1);
}
+ inode->i_size += SECTOR_SIZE*cluster_size;
+ MSDOS_I(inode)->i_realsize += SECTOR_SIZE*cluster_size;
+ mark_inode_dirty(inode);
return res;
}
-int fat_add_cluster(struct inode *inode)
-{
- struct buffer_head *bh = fat_add_cluster1(inode);
- if (!bh)
- return -ENOSPC;
- fat_brelse(inode->i_sb, bh);
- return 0;
-}
-
/* Linear day numbers of the respective 1sts in non-leap years. */
static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
@@ -351,7 +395,7 @@ int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
if (*bh)
fat_brelse(sb, *bh);
*bh = NULL;
- if ((sector = fat_smap(dir,offset >> SECTOR_BITS)) == -1)
+ if ((sector = fat_bmap(dir,offset >> SECTOR_BITS)) == -1)
return -1;
PRINTK (("get_entry sector %d %p\n",sector,*bh));
PRINTK (("get_entry sector apres brelse\n"));
diff --git a/fs/fcntl.c b/fs/fcntl.c
index d12e66244..26c9bf4a0 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -12,35 +12,89 @@
extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
-static inline int dupfd(struct file *file, unsigned int arg)
+/*
+ * locate_fd finds a free file descriptor in the open_fds fdset,
+ * expanding the fd arrays if necessary. The files write lock will be
+ * held on exit to ensure that the fd can be entered atomically.
+ */
+
+static inline int locate_fd(struct files_struct *files,
+ struct file *file, int start)
{
- struct files_struct * files = current->files;
+ unsigned int newfd;
int error;
- error = -EMFILE;
write_lock(&files->file_lock);
- arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg);
- if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur)
- goto out_putf;
- FD_SET(arg, &files->open_fds);
- FD_CLR(arg, &files->close_on_exec);
- write_unlock(&files->file_lock);
- fd_install(arg, file);
- error = arg;
+
+repeat:
+ error = -EMFILE;
+ if (start < files->next_fd)
+ start = files->next_fd;
+ if (start >= files->max_fdset) {
+ expand:
+ error = expand_files(files, start);
+ if (error < 0)
+ goto out;
+ goto repeat;
+ }
+
+ newfd = find_next_zero_bit(files->open_fds->fds_bits,
+ files->max_fdset, start);
+
+ error = -EMFILE;
+ if (newfd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
+ goto out;
+ if (newfd >= files->max_fdset)
+ goto expand;
+
+ error = expand_files(files, newfd);
+ if (error < 0)
+ goto out;
+ if (error) /* If we might have blocked, try again. */
+ goto repeat;
+
+ if (start <= files->next_fd)
+ files->next_fd = newfd + 1;
+
+ error = newfd;
+
out:
return error;
+}
+
+static inline void allocate_fd(struct files_struct *files,
+ struct file *file, int fd)
+{
+ FD_SET(fd, files->open_fds);
+ FD_CLR(fd, files->close_on_exec);
+ write_unlock(&files->file_lock);
+ fd_install(fd, file);
+}
+
+static int dupfd(struct file *file, int start)
+{
+ struct files_struct * files = current->files;
+ int ret;
+
+ ret = locate_fd(files, file, start);
+ if (ret < 0)
+ goto out_putf;
+ allocate_fd(files, file, ret);
+ return ret;
out_putf:
+ write_unlock(&files->file_lock);
fput(file);
- goto out;
+ return ret;
}
-asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
+asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd)
{
int err = -EBADF;
struct file * file;
+ struct files_struct * files = current->files;
- read_lock(&current->files->file_lock);
+ write_lock(&current->files->file_lock);
if (!(file = fcheck(oldfd)))
goto out_unlock;
err = newfd;
@@ -49,22 +103,41 @@ asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
err = -EBADF;
if (newfd >= NR_OPEN)
goto out_unlock; /* following POSIX.1 6.2.1 */
- get_file(file);
- read_unlock(&current->files->file_lock);
+ get_file(file); /* We are now finished with oldfd */
+
+ err = expand_files(files, newfd);
+ if (err < 0) {
+ write_unlock(&files->file_lock);
+ fput(file);
+ goto out;
+ }
+
+ /* To avoid races with open() and dup(), we will mark the fd as
+ * in-use in the open-file bitmap throughout the entire dup2()
+ * process. This is quite safe: do_close() uses the fd array
+ * entry, not the bitmap, to decide what work needs to be
+ * done. --sct */
+ FD_SET(newfd, files->open_fds);
+ write_unlock(&files->file_lock);
+
+ do_close(newfd, 0);
+
+ write_lock(&files->file_lock);
+ allocate_fd(files, file, newfd);
+ err = newfd;
- sys_close(newfd);
- err = dupfd(file, newfd);
out:
return err;
out_unlock:
- read_unlock(&current->files->file_lock);
+ write_unlock(&current->files->file_lock);
goto out;
}
-asmlinkage int sys_dup(unsigned int fildes)
+asmlinkage long sys_dup(unsigned int fildes)
{
int ret = -EBADF;
struct file * file = fget(fildes);
+
if (file)
ret = dupfd(file, 0);
return ret;
@@ -117,13 +190,13 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
}
break;
case F_GETFD:
- err = FD_ISSET(fd, &current->files->close_on_exec);
+ err = FD_ISSET(fd, current->files->close_on_exec);
break;
case F_SETFD:
if (arg&1)
- FD_SET(fd, &current->files->close_on_exec);
+ FD_SET(fd, current->files->close_on_exec);
else
- FD_CLR(fd, &current->files->close_on_exec);
+ FD_CLR(fd, current->files->close_on_exec);
break;
case F_GETFL:
err = filp->f_flags;
@@ -151,7 +224,6 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
err = filp->f_owner.pid;
break;
case F_SETOWN:
- err = 0;
filp->f_owner.pid = arg;
filp->f_owner.uid = current->uid;
filp->f_owner.euid = current->euid;
@@ -162,7 +234,8 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
err = filp->f_owner.signum;
break;
case F_SETSIG:
- if (arg <= 0 || arg > _NSIG) {
+ /* arg == 0 restores default behaviour. */
+ if (arg < 0 || arg > _NSIG) {
err = -EINVAL;
break;
}
@@ -171,10 +244,9 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
break;
default:
/* sockets need a few special fcntls. */
+ err = -EINVAL;
if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
err = sock_fcntl (filp, cmd, arg);
- else
- err = -EINVAL;
break;
}
fput(filp);
diff --git a/fs/fifo.c b/fs/fifo.c
index 3e641a6fe..757b2c4f4 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -12,38 +12,38 @@
#include <linux/mm.h>
#include <linux/malloc.h>
-static int fifo_open(struct inode * inode,struct file * filp)
+static int fifo_open(struct inode *inode, struct file *filp)
{
- int retval = 0;
- unsigned long page = 0;
- struct pipe_inode_info *info, *tmp = NULL;
-
- if (inode->i_pipe)
- goto got_it;
- tmp = kmalloc(sizeof(struct pipe_inode_info),GFP_KERNEL);
- if (inode->i_pipe)
- goto got_it;
- if (!tmp)
- goto oom;
- page = __get_free_page(GFP_KERNEL);
- if (inode->i_pipe)
- goto got_it;
- if (!page)
- goto oom;
- inode->i_pipe = tmp;
- PIPE_LOCK(*inode) = 0;
- PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
- PIPE_BASE(*inode) = (char *) page;
- PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
- PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
- init_waitqueue_head(&PIPE_WAIT(*inode));
- tmp = NULL; /* no need to free it */
- page = 0;
-
-got_it:
-
- switch( filp->f_mode ) {
+ int ret;
+ ret = -ERESTARTSYS;
+ if (down_interruptible(PIPE_SEM(*inode)))
+ goto err_nolock_nocleanup;
+
+ if (! inode->i_pipe) {
+ unsigned long page;
+ struct pipe_inode_info *info;
+
+ info = kmalloc(sizeof(struct pipe_inode_info),GFP_KERNEL);
+
+ ret = -ENOMEM;
+ if (!info)
+ goto err_nocleanup;
+ page = __get_free_page(GFP_KERNEL);
+ if (!page) {
+ kfree(info);
+ goto err_nocleanup;
+ }
+
+ inode->i_pipe = info;
+
+ init_waitqueue_head(PIPE_WAIT(*inode));
+ PIPE_BASE(*inode) = (char *) page;
+ PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
+ PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
+ }
+
+ switch (filp->f_mode) {
case 1:
/*
* O_RDONLY
@@ -51,26 +51,26 @@ got_it:
* opened, even when there is no process writing the FIFO.
*/
filp->f_op = &connecting_fifo_fops;
- if (!PIPE_READERS(*inode)++)
- wake_up_interruptible(&PIPE_WAIT(*inode));
- if (!(filp->f_flags & O_NONBLOCK) && !PIPE_WRITERS(*inode)) {
- PIPE_RD_OPENERS(*inode)++;
+ if (PIPE_READERS(*inode)++ == 0)
+ wake_up_interruptible(PIPE_WAIT(*inode));
+
+ if (!(filp->f_flags & O_NONBLOCK)) {
while (!PIPE_WRITERS(*inode)) {
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- interruptible_sleep_on(&PIPE_WAIT(*inode));
+ if (signal_pending(current))
+ goto err_rd;
+ up(PIPE_SEM(*inode));
+ interruptible_sleep_on(PIPE_WAIT(*inode));
+
+ /* Note that using down_interruptible here
+ and similar places below is pointless,
+ since we have to acquire the lock to clean
+ up properly. */
+ down(PIPE_SEM(*inode));
}
- if (!--PIPE_RD_OPENERS(*inode))
- wake_up_interruptible(&PIPE_WAIT(*inode));
}
- while (PIPE_WR_OPENERS(*inode))
- interruptible_sleep_on(&PIPE_WAIT(*inode));
+
if (PIPE_WRITERS(*inode))
filp->f_op = &read_fifo_fops;
- if (retval && !--PIPE_READERS(*inode))
- wake_up_interruptible(&PIPE_WAIT(*inode));
break;
case 2:
@@ -79,29 +79,21 @@ got_it:
* POSIX.1 says that O_NONBLOCK means return -1 with
* errno=ENXIO when there is no process reading the FIFO.
*/
- if ((filp->f_flags & O_NONBLOCK) && !PIPE_READERS(*inode)) {
- retval = -ENXIO;
- break;
- }
+ ret = -ENXIO;
+ if ((filp->f_flags & O_NONBLOCK) && !PIPE_READERS(*inode))
+ goto err;
+
filp->f_op = &write_fifo_fops;
if (!PIPE_WRITERS(*inode)++)
- wake_up_interruptible(&PIPE_WAIT(*inode));
- if (!PIPE_READERS(*inode)) {
- PIPE_WR_OPENERS(*inode)++;
- while (!PIPE_READERS(*inode)) {
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- interruptible_sleep_on(&PIPE_WAIT(*inode));
- }
- if (!--PIPE_WR_OPENERS(*inode))
- wake_up_interruptible(&PIPE_WAIT(*inode));
+ wake_up_interruptible(PIPE_WAIT(*inode));
+
+ while (!PIPE_READERS(*inode)) {
+ if (signal_pending(current))
+ goto err_wr;
+ up(PIPE_SEM(*inode));
+ interruptible_sleep_on(PIPE_WAIT(*inode));
+ down(PIPE_SEM(*inode));
}
- while (PIPE_RD_OPENERS(*inode))
- interruptible_sleep_on(&PIPE_WAIT(*inode));
- if (retval && !--PIPE_WRITERS(*inode))
- wake_up_interruptible(&PIPE_WAIT(*inode));
break;
case 3:
@@ -112,39 +104,47 @@ got_it:
* the process can at least talk to itself.
*/
filp->f_op = &rdwr_fifo_fops;
- if (!PIPE_READERS(*inode)++)
- wake_up_interruptible(&PIPE_WAIT(*inode));
- while (PIPE_WR_OPENERS(*inode))
- interruptible_sleep_on(&PIPE_WAIT(*inode));
- if (!PIPE_WRITERS(*inode)++)
- wake_up_interruptible(&PIPE_WAIT(*inode));
- while (PIPE_RD_OPENERS(*inode))
- interruptible_sleep_on(&PIPE_WAIT(*inode));
+
+ PIPE_READERS(*inode)++;
+ PIPE_WRITERS(*inode)++;
+ if (PIPE_READERS(*inode) == 1 || PIPE_WRITERS(*inode) == 1)
+ wake_up_interruptible(PIPE_WAIT(*inode));
break;
default:
- retval = -EINVAL;
+ ret = -EINVAL;
+ goto err;
}
- if (retval)
- goto cleanup;
-out:
- if (tmp)
- kfree(tmp);
- if (page)
- free_page(page);
- return retval;
-
-cleanup:
+
+ /* Ok! */
+ up(PIPE_SEM(*inode));
+ return 0;
+
+err_rd:
+ if (!--PIPE_READERS(*inode))
+ wake_up_interruptible(PIPE_WAIT(*inode));
+ ret = -ERESTARTSYS;
+ goto err;
+
+err_wr:
+ if (!--PIPE_WRITERS(*inode))
+ wake_up_interruptible(PIPE_WAIT(*inode));
+ ret = -ERESTARTSYS;
+ goto err;
+
+err:
if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) {
- info = inode->i_pipe;
+ struct pipe_inode_info *info = inode->i_pipe;
inode->i_pipe = NULL;
free_page((unsigned long)info->base);
kfree(info);
}
- goto out;
-oom:
- retval = -ENOMEM;
- goto out;
+
+err_nocleanup:
+ up(PIPE_SEM(*inode));
+
+err_nolock_nocleanup:
+ return ret;
}
/*
diff --git a/fs/file.c b/fs/file.c
new file mode 100644
index 000000000..fd33dc8b8
--- /dev/null
+++ b/fs/file.c
@@ -0,0 +1,240 @@
+/*
+ * linux/fs/open.c
+ *
+ * Copyright (C) 1998-1999, Stephen Tweedie and Bill Hawes
+ *
+ * Manage the dynamic fd arrays in the process files_struct.
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+
+#include <asm/bitops.h>
+
+
+/*
+ * Allocate an fd array, using get_free_page() if possible.
+ * Note: the array isn't cleared at allocation time.
+ */
+struct file ** alloc_fd_array(int num)
+{
+ struct file **new_fds;
+ int size = num * sizeof(struct file *);
+
+ if (size < PAGE_SIZE)
+ new_fds = (struct file **) kmalloc(size, GFP_KERNEL);
+ else if (size == PAGE_SIZE)
+ new_fds = (struct file **) __get_free_page(GFP_KERNEL);
+ else
+ new_fds = (struct file **) vmalloc(size);
+ return new_fds;
+}
+
+void free_fd_array(struct file **array, int num)
+{
+ int size = num * sizeof(struct file *);
+
+ if (!array) {
+ printk (KERN_ERR __FUNCTION__ "array = 0 (num = %d)\n", num);
+ return;
+ }
+
+ if (num <= NR_OPEN_DEFAULT) /* Don't free the embedded fd array! */
+ return;
+ else if (size < PAGE_SIZE)
+ kfree(array);
+ else if (size == PAGE_SIZE)
+ free_page((unsigned long) array);
+ else
+ vfree(array);
+}
+
+/*
+ * Expand the fd array in the files_struct. Called with the files
+ * spinlock held for write.
+ */
+
+int expand_fd_array(struct files_struct *files, int nr)
+{
+ struct file **new_fds;
+ int error, nfds;
+
+
+ error = -EMFILE;
+ if (files->max_fds >= NR_OPEN || nr > NR_OPEN)
+ goto out;
+
+ nfds = files->max_fds;
+ write_unlock(&files->file_lock);
+
+ /*
+ * Expand to the max in easy steps, and keep expanding it until
+ * we have enough for the requested fd array size.
+ */
+
+ do {
+#if NR_OPEN_DEFAULT < 256
+ if (nfds < 256)
+ nfds = 256;
+ else
+#endif
+ if (nfds < (PAGE_SIZE / sizeof(struct file *)))
+ nfds = PAGE_SIZE / sizeof(struct file *);
+ else {
+ nfds = nfds * 2;
+ if (nfds > NR_OPEN)
+ nfds = NR_OPEN;
+ }
+ } while (nfds < nr);
+
+ error = -ENOMEM;
+ new_fds = alloc_fd_array(nfds);
+ write_lock(&files->file_lock);
+ if (!new_fds)
+ goto out;
+
+ /* Copy the existing array and install the new pointer */
+
+ if (nfds > files->max_fds) {
+ struct file **old_fds;
+ int i;
+
+ old_fds = xchg(&files->fd, new_fds);
+ i = xchg(&files->max_fds, nfds);
+
+ /* Don't copy/clear the array if we are creating a new
+ fd array for fork() */
+ if (i) {
+ memcpy(new_fds, old_fds, i * sizeof(struct file *));
+ /* clear the remainder of the array */
+ memset(&new_fds[i], 0,
+ (nfds-i) * sizeof(struct file *));
+
+ write_unlock(&files->file_lock);
+ free_fd_array(old_fds, i);
+ write_lock(&files->file_lock);
+ }
+ } else {
+ /* Somebody expanded the array while we slept ... */
+ write_unlock(&files->file_lock);
+ free_fd_array(new_fds, nfds);
+ write_lock(&files->file_lock);
+ }
+ error = 0;
+out:
+ return error;
+}
+
+/*
+ * Allocate an fdset array, using get_free_page() if possible.
+ * Note: the array isn't cleared at allocation time.
+ */
+fd_set * alloc_fdset(int num)
+{
+ fd_set *new_fdset;
+ int size = num / 8;
+
+ if (size < PAGE_SIZE)
+ new_fdset = (fd_set *) kmalloc(size, GFP_KERNEL);
+ else if (size == PAGE_SIZE)
+ new_fdset = (fd_set *) __get_free_page(GFP_KERNEL);
+ else
+ new_fdset = (fd_set *) vmalloc(size);
+ return new_fdset;
+}
+
+void free_fdset(fd_set *array, int num)
+{
+ int size = num / 8;
+
+ if (!array) {
+ printk (KERN_ERR __FUNCTION__ "array = 0 (num = %d)\n", num);
+ return;
+ }
+
+ if (num <= __FD_SETSIZE) /* Don't free an embedded fdset */
+ return;
+ else if (size < PAGE_SIZE)
+ kfree(array);
+ else if (size == PAGE_SIZE)
+ free_page((unsigned long) array);
+ else
+ vfree(array);
+}
+
+/*
+ * Expand the fdset in the files_struct. Called with the files spinlock
+ * held for write.
+ */
+int expand_fdset(struct files_struct *files, int nr)
+{
+ fd_set *new_openset = 0, *new_execset = 0;
+ int error, nfds = 0;
+
+ error = -EMFILE;
+ if (files->max_fdset >= NR_OPEN || nr > NR_OPEN)
+ goto out;
+
+ nfds = files->max_fdset;
+ write_unlock(&files->file_lock);
+
+ /* Expand to the max in easy steps */
+ do {
+ if (nfds < (PAGE_SIZE * 8))
+ nfds = PAGE_SIZE * 8;
+ else {
+ nfds = nfds * 2;
+ if (nfds > NR_OPEN)
+ nfds = NR_OPEN;
+ }
+ } while (nfds < nr);
+
+ error = -ENOMEM;
+ new_openset = alloc_fdset(nfds);
+ new_execset = alloc_fdset(nfds);
+ write_lock(&files->file_lock);
+ if (!new_openset || !new_execset)
+ goto out;
+
+ error = 0;
+
+ /* Copy the existing tables and install the new pointers */
+ if (nfds > files->max_fdset) {
+ int i = files->max_fdset / (sizeof(unsigned long) * 8);
+ int count = (nfds - files->max_fdset) / 8;
+
+ /*
+ * Don't copy the entire array if the current fdset is
+ * not yet initialised.
+ */
+ if (i) {
+ memcpy (new_openset, files->open_fds, files->max_fdset/8);
+ memcpy (new_execset, files->close_on_exec, files->max_fdset/8);
+ memset (&new_openset->fds_bits[i], 0, count);
+ memset (&new_execset->fds_bits[i], 0, count);
+ }
+
+ nfds = xchg(&files->max_fdset, nfds);
+ new_openset = xchg(&files->open_fds, new_openset);
+ new_execset = xchg(&files->close_on_exec, new_execset);
+ write_unlock(&files->file_lock);
+ free_fdset (new_openset, nfds);
+ free_fdset (new_execset, nfds);
+ write_lock(&files->file_lock);
+ return 0;
+ }
+ /* Somebody expanded the array while we slept ... */
+
+out:
+ write_unlock(&files->file_lock);
+ if (new_openset)
+ free_fdset(new_openset, nfds);
+ if (new_execset)
+ free_fdset(new_execset, nfds);
+ write_lock(&files->file_lock);
+ return error;
+}
+
diff --git a/fs/file_table.c b/fs/file_table.c
index cb9ef16e9..ee2f4e788 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -116,16 +116,29 @@ int init_private_file(struct file *filp, struct dentry *dentry, int mode)
return 0;
}
-void _fput(struct file *file)
+/*
+ * Called when retiring the last use of a file pointer.
+ */
+static void __fput(struct file *filp)
{
- atomic_inc(&file->f_count);
+ struct dentry * dentry = filp->f_dentry;
+ struct inode * inode = dentry->d_inode;
+
+ if (filp->f_op && filp->f_op->release)
+ filp->f_op->release(inode, filp);
+ filp->f_dentry = NULL;
+ if (filp->f_mode & FMODE_WRITE)
+ put_write_access(inode);
+ dput(dentry);
+}
+void _fput(struct file *file)
+{
lock_kernel();
locks_remove_flock(file); /* Still need the */
__fput(file); /* big lock here. */
unlock_kernel();
- atomic_set(&file->f_count, 0);
file_list_lock();
list_del(&file->f_list);
list_add(&file->f_list, &free_list);
@@ -182,7 +195,7 @@ int fs_may_remount_ro(struct super_block *sb)
/* Writable file? */
if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE))
- return 0;
+ goto too_bad;
}
file_list_unlock();
return 1; /* Tis' cool bro. */
diff --git a/fs/filesystems.c b/fs/filesystems.c
index ee3f32c67..b05b3b657 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -26,6 +26,7 @@
#include <linux/romfs_fs.h>
#include <linux/auto_fs.h>
#include <linux/qnx4_fs.h>
+#include <linux/udf_fs.h>
#include <linux/ntfs_fs.h>
#include <linux/hfs_fs.h>
#include <linux/devpts_fs.h>
@@ -149,6 +150,10 @@ void __init filesystem_setup(void)
#ifdef CONFIG_QNX4FS_FS
init_qnx4_fs();
#endif
+
+#ifdef CONFIG_UDF_FS
+ init_udf_fs();
+#endif
#ifdef CONFIG_NLS
init_nls();
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index cae7bbf72..cb10a760c 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -493,7 +493,7 @@ bail3:
return NULL;
}
-__initfunc(int init_hfs_fs(void))
+int __init init_hfs_fs(void)
{
hfs_cat_init();
return register_filesystem(&hfs_fs);
diff --git a/fs/inode.c b/fs/inode.c
index 242696d87..66f76f927 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -103,7 +103,7 @@ static void __wait_on_inode(struct inode * inode)
add_wait_queue(&inode->i_wait, &wait);
repeat:
- current->state = TASK_UNINTERRUPTIBLE;
+ set_current_state(TASK_UNINTERRUPTIBLE);
if (inode->i_state & I_LOCK) {
schedule();
goto repeat;
diff --git a/fs/iobuf.c b/fs/iobuf.c
new file mode 100644
index 000000000..b46a13bfd
--- /dev/null
+++ b/fs/iobuf.c
@@ -0,0 +1,136 @@
+/*
+ * iobuf.c
+ *
+ * Keep track of the general-purpose IO-buffer structures used to track
+ * abstract kernel-space io buffers.
+ *
+ */
+
+#include <linux/iobuf.h>
+#include <linux/malloc.h>
+#include <linux/slab.h>
+
+static kmem_cache_t *kiobuf_cachep;
+
+/*
+ * The default IO completion routine for kiobufs: just wake up
+ * the kiobuf, nothing more.
+ */
+
+void simple_wakeup_kiobuf(struct kiobuf *kiobuf)
+{
+ wake_up(&kiobuf->wait_queue);
+}
+
+
+void __init kiobuf_init(void)
+{
+ kiobuf_cachep = kmem_cache_create("kiobuf",
+ sizeof(struct kiobuf),
+ 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if(!kiobuf_cachep)
+ panic("Cannot create kernel iobuf cache\n");
+}
+
+
+int alloc_kiovec(int nr, struct kiobuf **bufp)
+{
+ int i;
+ struct kiobuf *iobuf;
+
+ for (i = 0; i < nr; i++) {
+ iobuf = kmem_cache_alloc(kiobuf_cachep, SLAB_KERNEL);
+ if (!iobuf) {
+ free_kiovec(i, bufp);
+ return -ENOMEM;
+ }
+
+ memset(iobuf, 0, sizeof(*iobuf));
+ init_waitqueue_head(&iobuf->wait_queue);
+ iobuf->end_io = simple_wakeup_kiobuf;
+ iobuf->array_len = KIO_STATIC_PAGES;
+ iobuf->pagelist = iobuf->page_array;
+ iobuf->maplist = iobuf->map_array;
+ *bufp++ = iobuf;
+ }
+
+ return 0;
+}
+
+void free_kiovec(int nr, struct kiobuf **bufp)
+{
+ int i;
+ struct kiobuf *iobuf;
+
+ for (i = 0; i < nr; i++) {
+ iobuf = bufp[i];
+ if (iobuf->array_len > KIO_STATIC_PAGES) {
+ kfree (iobuf->pagelist);
+ kfree (iobuf->maplist);
+ }
+ kmem_cache_free(kiobuf_cachep, bufp[i]);
+ }
+}
+
+int expand_kiobuf(struct kiobuf *iobuf, int wanted)
+{
+ unsigned long * pagelist;
+ struct page ** maplist;
+
+ if (iobuf->array_len >= wanted)
+ return 0;
+
+ pagelist = (unsigned long *)
+ kmalloc(wanted * sizeof(unsigned long), GFP_KERNEL);
+ if (!pagelist)
+ return -ENOMEM;
+
+ maplist = (struct page **)
+ kmalloc(wanted * sizeof(struct page **), GFP_KERNEL);
+ if (!maplist) {
+ kfree(pagelist);
+ return -ENOMEM;
+ }
+
+ /* Did it grow while we waited? */
+ if (iobuf->array_len >= wanted) {
+ kfree(pagelist);
+ kfree(maplist);
+ return 0;
+ }
+
+ memcpy (pagelist, iobuf->pagelist, wanted * sizeof(unsigned long));
+ memcpy (maplist, iobuf->maplist, wanted * sizeof(struct page **));
+
+ if (iobuf->array_len > KIO_STATIC_PAGES) {
+ kfree (iobuf->pagelist);
+ kfree (iobuf->maplist);
+ }
+
+ iobuf->pagelist = pagelist;
+ iobuf->maplist = maplist;
+ iobuf->array_len = wanted;
+ return 0;
+}
+
+
+void kiobuf_wait_for_io(struct kiobuf *kiobuf)
+{
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+
+ add_wait_queue(&kiobuf->wait_queue, &wait);
+repeat:
+ run_task_queue(&tq_disk);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (atomic_read(&kiobuf->io_count) != 0) {
+ schedule();
+ goto repeat;
+ }
+ tsk->state = TASK_RUNNING;
+ remove_wait_queue(&kiobuf->wait_queue, &wait);
+}
+
+
+
diff --git a/fs/ioctl.c b/fs/ioctl.c
index b9f2363e6..e7e226056 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -48,7 +48,7 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
}
-asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
unsigned int flag;
@@ -61,11 +61,11 @@ asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
lock_kernel();
switch (cmd) {
case FIOCLEX:
- FD_SET(fd, &current->files->close_on_exec);
+ FD_SET(fd, current->files->close_on_exec);
break;
case FIONCLEX:
- FD_CLR(fd, &current->files->close_on_exec);
+ FD_CLR(fd, current->files->close_on_exec);
break;
case FIONBIO:
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 1cf86ae63..f055c52e0 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -1469,7 +1469,7 @@ static struct file_system_type iso9660_fs_type = {
NULL
};
-__initfunc(int init_iso9660_fs(void))
+int __init init_iso9660_fs(void)
{
return register_filesystem(&iso9660_fs_type);
}
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index efda2a30d..7a4674d85 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -172,7 +172,7 @@ reclaimer(void *ptr)
/* First, reclaim all locks that have been granted previously. */
do {
- for (fl = file_lock_table; fl; fl = fl->fl_next) {
+ for (fl = file_lock_table; fl; fl = fl->fl_nextlink) {
inode = fl->fl_file->f_dentry->d_inode;
if (inode->i_sb->s_magic == NFS_SUPER_MAGIC
&& nlm_cmp_addr(NFS_ADDR(inode), &host->h_addr)
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 10c66ed4d..73caf6349 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -335,9 +335,12 @@ again:
/* Append to list of blocked */
nlmsvc_insert_block(block, NLM_NEVER);
- /* Now add block to block list of the conflicting lock */
- dprintk("lockd: blocking on this lock.\n");
- posix_block_lock(conflock, &block->b_call.a_args.lock.fl);
+ if (!block->b_call.a_args.lock.fl.fl_prevblock) {
+ /* Now add block to block list of the conflicting lock
+ if we haven't done so. */
+ dprintk("lockd: blocking on this lock.\n");
+ posix_block_lock(conflock, &block->b_call.a_args.lock.fl);
+ }
up(&file->f_sema);
return nlm_lck_blocked;
@@ -440,7 +443,7 @@ nlmsvc_notify_blocked(struct file_lock *fl)
dprintk("lockd: VFS unblock notification for block %p\n", fl);
posix_unblock_lock(fl);
for (bp = &nlm_blocked; (block = *bp); bp = &block->b_next) {
- if (&block->b_call.a_args.lock.fl == fl) {
+ if (nlm_compare_locks(&block->b_call.a_args.lock.fl, fl)) {
svc_wake_up(block->b_daemon);
nlmsvc_insert_block(block, 0);
return;
diff --git a/fs/locks.c b/fs/locks.c
index 5cb324374..802958a68 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -193,6 +193,14 @@ static void locks_insert_block(struct file_lock *blocker,
{
struct file_lock *prevblock;
+ if (waiter->fl_prevblock) {
+ printk(KERN_ERR "locks_insert_block: remove duplicated lock "
+ "(pid=%d %ld-%ld type=%d)\n",
+ waiter->fl_pid, waiter->fl_start,
+ waiter->fl_end, waiter->fl_type);
+ locks_delete_block(waiter->fl_prevblock, waiter);
+ }
+
if (blocker->fl_prevblock == NULL)
/* No previous waiters - list is empty */
prevblock = blocker;
@@ -282,7 +290,7 @@ static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait)
/* flock() system call entry point. Apply a FL_FLOCK style lock to
* an open file descriptor.
*/
-asmlinkage int sys_flock(unsigned int fd, unsigned int cmd)
+asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
{
struct file_lock file_lock;
struct file *filp;
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 8c396f3e6..060d5b26c 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -16,6 +16,8 @@
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
#include <asm/bitops.h>
@@ -51,8 +53,9 @@ static unsigned long count_free(struct buffer_head *map[], unsigned numblocks, _
return(sum);
}
-void minix_free_block(struct super_block * sb, int block)
+void minix_free_block(struct inode * inode, int block)
{
+ struct super_block * sb = inode->i_sb;
struct buffer_head * bh;
unsigned int bit,zone;
@@ -80,12 +83,15 @@ void minix_free_block(struct super_block * sb, int block)
if (!minix_clear_bit(bit,bh->b_data))
printk("free_block (%s:%d): bit already cleared\n",
kdevname(sb->s_dev), block);
+ else
+ DQUOT_FREE_BLOCK(sb, inode, 1);
mark_buffer_dirty(bh, 1);
return;
}
-int minix_new_block(struct super_block * sb)
+int minix_new_block(struct inode * inode)
{
+ struct super_block * sb = inode->i_sb;
struct buffer_head * bh;
int i,j;
@@ -94,6 +100,9 @@ int minix_new_block(struct super_block * sb)
return 0;
}
repeat:
+ if(DQUOT_ALLOC_BLOCK(sb, inode, 1))
+ return -EDQUOT;
+
j = 8192;
bh = NULL;
for (i = 0; i < sb->u.minix_sb.s_zmap_blocks; i++) {
@@ -105,6 +114,7 @@ repeat:
return 0;
if (minix_set_bit(j,bh->b_data)) {
printk("new_block: bit already set");
+ DQUOT_FREE_BLOCK(sb, inode, 1);
goto repeat;
}
mark_buffer_dirty(bh, 1);
@@ -222,6 +232,10 @@ void minix_free_inode(struct inode * inode)
printk("free_inode: nonexistent imap in superblock\n");
return;
}
+
+ DQUOT_FREE_INODE(inode->i_sb, inode);
+ DQUOT_DROP(inode);
+
bh = inode->i_sb->u.minix_sb.s_imap[ino >> 13];
minix_clear_inode(inode);
clear_inode(inode);
@@ -230,7 +244,7 @@ void minix_free_inode(struct inode * inode)
mark_buffer_dirty(bh, 1);
}
-struct inode * minix_new_inode(const struct inode * dir)
+struct inode * minix_new_inode(const struct inode * dir, int * error)
{
struct super_block * sb;
struct inode * inode;
@@ -274,6 +288,20 @@ struct inode * minix_new_inode(const struct inode * dir)
inode->i_blocks = inode->i_blksize = 0;
insert_inode_hash(inode);
mark_inode_dirty(inode);
+
+ unlock_super(sb);
+printk("m_n_i: allocated inode ");
+ if(DQUOT_ALLOC_INODE(sb, inode)) {
+printk("fails quota test\n");
+ sb->dq_op->drop(inode);
+ inode->i_nlink = 0;
+ iput(inode);
+ *error = -EDQUOT;
+ return NULL;
+ }
+printk("is within quota\n");
+
+ *error = 0;
return inode;
}
diff --git a/fs/minix/file.c b/fs/minix/file.c
index 9eab1fb17..6683c393c 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -24,6 +24,7 @@
#define MAX(a,b) (((a)>(b))?(a):(b))
#include <linux/fs.h>
+#include <linux/minix_fs.h>
/*
* Write to a file (through the page cache).
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index e5352090d..6cc9522fa 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -518,7 +518,7 @@ repeat:
}
}
- tmp = minix_new_block(inode->i_sb);
+ tmp = minix_new_block(inode);
if (!tmp) {
*err = -ENOSPC;
return NULL;
@@ -526,7 +526,7 @@ repeat:
if (metadata) {
result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
if (*p) {
- minix_free_block(inode->i_sb, tmp);
+ minix_free_block(inode, tmp);
brelse(result);
goto repeat;
}
@@ -540,7 +540,7 @@ repeat:
* state from under us:
*/
BUG();
- minix_free_block(inode->i_sb, tmp);
+ minix_free_block(inode, tmp);
goto repeat;
}
*phys = tmp;
@@ -599,13 +599,13 @@ repeat:
}
}
- tmp = minix_new_block(inode->i_sb);
+ tmp = minix_new_block(inode);
if (!tmp)
goto out;
if (metadata) {
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
if (*p) {
- minix_free_block(inode->i_sb, tmp);
+ minix_free_block(inode, tmp);
brelse(result);
goto repeat;
}
@@ -617,7 +617,7 @@ repeat:
*new = 1;
}
if (*p) {
- minix_free_block(inode->i_sb, tmp);
+ minix_free_block(inode, tmp);
brelse(result);
goto repeat;
}
@@ -754,7 +754,7 @@ repeat:
}
}
- tmp = minix_new_block(inode->i_sb);
+ tmp = minix_new_block(inode);
if (!tmp) {
*err = -ENOSPC;
return NULL;
@@ -762,7 +762,7 @@ repeat:
if (metadata) {
result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
if (*p) {
- minix_free_block(inode->i_sb, tmp);
+ minix_free_block(inode, tmp);
brelse(result);
goto repeat;
}
@@ -776,7 +776,7 @@ repeat:
* state from under us:
*/
BUG();
- minix_free_block(inode->i_sb, tmp);
+ minix_free_block(inode, tmp);
goto repeat;
}
*phys = tmp;
@@ -835,13 +835,13 @@ repeat:
}
}
- tmp = minix_new_block(inode->i_sb);
+ tmp = minix_new_block(inode);
if (!tmp)
goto out;
if (metadata) {
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
if (*p) {
- minix_free_block(inode->i_sb, tmp);
+ minix_free_block(inode, tmp);
brelse(result);
goto repeat;
}
@@ -853,7 +853,7 @@ repeat:
*new = 1;
}
if (*p) {
- minix_free_block(inode->i_sb, tmp);
+ minix_free_block(inode, tmp);
brelse(result);
goto repeat;
}
@@ -1238,7 +1238,7 @@ static struct file_system_type minix_fs_type = {
NULL
};
-__initfunc(int init_minix_fs(void))
+int __init init_minix_fs(void)
{
return register_filesystem(&minix_fs_type);
}
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index ae5aa8a5a..b268a4676 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -11,6 +11,7 @@
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
+#include <linux/quotaops.h>
#include <asm/uaccess.h>
@@ -212,7 +213,9 @@ int minix_create(struct inode * dir, struct dentry *dentry, int mode)
struct buffer_head * bh;
struct minix_dir_entry * de;
- inode = minix_new_inode(dir);
+ inode = minix_new_inode(dir, &error);
+ if (error)
+ return error;
if (!inode)
return -ENOSPC;
inode->i_op = &minix_file_inode_operations;
@@ -240,7 +243,9 @@ int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev)
struct buffer_head * bh;
struct minix_dir_entry * de;
- inode = minix_new_inode(dir);
+ inode = minix_new_inode(dir, &error);
+ if (error)
+ return error;
if (!inode)
return -ENOSPC;
inode->i_uid = current->fsuid;
@@ -271,7 +276,9 @@ int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
info = &dir->i_sb->u.minix_sb;
if (dir->i_nlink >= info->s_link_max)
return -EMLINK;
- inode = minix_new_inode(dir);
+ inode = minix_new_inode(dir, &error);
+ if (error)
+ return error;
if (!inode)
return -ENOSPC;
inode->i_op = &minix_dir_inode_operations;
@@ -383,6 +390,7 @@ int minix_rmdir(struct inode * dir, struct dentry *dentry)
if (!bh)
goto end_rmdir;
inode = dentry->d_inode;
+ DQUOT_INIT(inode);
if (!empty_dir(inode)) {
retval = -ENOTEMPTY;
@@ -422,6 +430,7 @@ int minix_unlink(struct inode * dir, struct dentry *dentry)
retval = -ENOENT;
inode = dentry->d_inode;
+ DQUOT_INIT(inode);
bh = minix_find_entry(dir, dentry->d_name.name,
dentry->d_name.len, &de);
if (!bh || de->inode != inode->i_ino)
@@ -456,7 +465,10 @@ int minix_symlink(struct inode * dir, struct dentry *dentry,
int i;
char c;
- if (!(inode = minix_new_inode(dir)))
+ inode = minix_new_inode(dir, &i);
+ if (i)
+ return i;
+ if (!inode)
return -ENOSPC;
inode->i_mode = S_IFLNK | 0777;
@@ -554,6 +566,8 @@ int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
if (!new_inode) {
brelse(new_bh);
new_bh = NULL;
+ } else {
+ DQUOT_INIT(new_inode);
}
}
if (S_ISDIR(old_inode->i_mode)) {
diff --git a/fs/minix/truncate.c b/fs/minix/truncate.c
index 6724d0064..f26aa086c 100644
--- a/fs/minix/truncate.c
+++ b/fs/minix/truncate.c
@@ -62,11 +62,8 @@ repeat:
}
*p = 0;
mark_inode_dirty(inode);
- if (bh) {
- mark_buffer_clean(bh);
- brelse(bh);
- }
- minix_free_block(inode->i_sb,tmp);
+ bforget(bh);
+ minix_free_block(inode,tmp);
}
return retry;
}
@@ -113,8 +110,8 @@ repeat:
}
*ind = 0;
mark_buffer_dirty(ind_bh, 1);
- brelse(bh);
- minix_free_block(inode->i_sb,tmp);
+ bforget(bh);
+ minix_free_block(inode,tmp);
}
ind = (unsigned short *) ind_bh->b_data;
for (i = 0; i < 512; i++)
@@ -126,7 +123,7 @@ repeat:
else {
tmp = *p;
*p = 0;
- minix_free_block(inode->i_sb,tmp);
+ minix_free_block(inode,tmp);
}
}
brelse(ind_bh);
@@ -172,7 +169,7 @@ repeat:
tmp = *p;
*p = 0;
mark_inode_dirty(inode);
- minix_free_block(inode->i_sb,tmp);
+ minix_free_block(inode,tmp);
}
}
brelse(dind_bh);
@@ -226,11 +223,8 @@ repeat:
}
*p = 0;
mark_inode_dirty(inode);
- if (bh) {
- mark_buffer_clean(bh);
- brelse(bh);
- }
- minix_free_block(inode->i_sb,tmp);
+ bforget(bh);
+ minix_free_block(inode,tmp);
}
return retry;
}
@@ -277,8 +271,8 @@ repeat:
}
*ind = 0;
mark_buffer_dirty(ind_bh, 1);
- brelse(bh);
- minix_free_block(inode->i_sb,tmp);
+ bforget(bh);
+ minix_free_block(inode,tmp);
}
ind = (unsigned long *) ind_bh->b_data;
for (i = 0; i < 256; i++)
@@ -290,7 +284,7 @@ repeat:
else {
tmp = *p;
*p = 0;
- minix_free_block(inode->i_sb,tmp);
+ minix_free_block(inode,tmp);
}
}
brelse(ind_bh);
@@ -336,7 +330,7 @@ repeat:
tmp = *p;
*p = 0;
mark_inode_dirty(inode);
- minix_free_block(inode->i_sb,tmp);
+ minix_free_block(inode,tmp);
}
}
brelse(dind_bh);
@@ -382,7 +376,7 @@ repeat:
tmp = *p;
*p = 0;
mark_inode_dirty(inode);
- minix_free_block(inode->i_sb,tmp);
+ minix_free_block(inode,tmp);
}
}
brelse(tind_bh);
@@ -406,7 +400,8 @@ static void V2_minix_truncate(struct inode * inode)
(unsigned long *) inode->u.minix_i.u.i2_data + 9);
if (!retry)
break;
- current->counter = 0;
+ run_task_queue(&tq_disk);
+ current->policy |= SCHED_YIELD;
schedule();
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
diff --git a/fs/msdos/msdosfs_syms.c b/fs/msdos/msdosfs_syms.c
index b44c669ce..df865b482 100644
--- a/fs/msdos/msdosfs_syms.c
+++ b/fs/msdos/msdosfs_syms.c
@@ -34,7 +34,7 @@ struct file_system_type msdos_fs_type = {
NULL
};
-__initfunc(int init_msdos_fs(void))
+int __init init_msdos_fs(void)
{
return register_filesystem(&msdos_fs_type);
}
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index fa5e4aed5..d69aba48d 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -8,7 +8,6 @@
#define __NO_VERSION__
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -26,23 +25,18 @@
/* MS-DOS "device special files" */
static const char *reserved_names[] = {
-#ifndef CONFIG_ATARI /* GEMDOS is less stupid */
"CON ","PRN ","NUL ","AUX ",
"LPT1 ","LPT2 ","LPT3 ","LPT4 ",
"COM1 ","COM2 ","COM3 ","COM4 ",
-#endif
NULL };
/* Characters that are undesirable in an MS-DOS file name */
static char bad_chars[] = "*?<>|\"";
-#ifdef CONFIG_ATARI
-/* GEMDOS is less restrictive */
-static char bad_if_strict[] = " ";
-#else
-static char bad_if_strict[] = "+=,; ";
-#endif
+static char bad_if_strict_pc[] = "+=,; ";
+static char bad_if_strict_atari[] = " "; /* GEMDOS is less restrictive */
+#define bad_if_strict(opts) ((opts)->atari ? bad_if_strict_atari : bad_if_strict_pc)
/* Must die */
void msdos_put_super(struct super_block *sb)
@@ -51,8 +45,8 @@ void msdos_put_super(struct super_block *sb)
}
/***** Formats an MS-DOS file name. Rejects invalid names. */
-static int msdos_format_name(char conv,const char *name,int len,
- char *res,char dotsOK)
+static int msdos_format_name(const char *name,int len,
+ char *res,struct fat_mount_options *opts)
/* conv is relaxed/normal/strict, name is proposed name,
* len is the length of the proposed name, res is the result name,
* dotsOK is if hidden files get dots.
@@ -62,23 +56,27 @@ static int msdos_format_name(char conv,const char *name,int len,
const char **reserved;
unsigned char c;
int space;
+
if (name[0] == '.') { /* dotfile because . and .. already done */
- if (!dotsOK) return -EINVAL;
- /* Get rid of dot - test for it elsewhere */
- name++; len--;
+ if (opts->dotsOK) {
+ /* Get rid of dot - test for it elsewhere */
+ name++; len--;
+ }
+ else if (!opts->atari) return -EINVAL;
}
-#ifndef CONFIG_ATARI
- space = 1; /* disallow names that _really_ start with a dot */
-#else
- space = 0; /* GEMDOS does not care */
-#endif
+ /* disallow names that _really_ start with a dot for MS-DOS, GEMDOS does
+ * not care */
+ space = !opts->atari;
c = 0;
for (walk = res; len && walk-res < 8; walk++) {
c = *name++;
len--;
- if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
- if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
- if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
+ if (opts->conversion != 'r' && strchr(bad_chars,c))
+ return -EINVAL;
+ if (opts->conversion == 's' && strchr(bad_if_strict(opts),c))
+ return -EINVAL;
+ if (c >= 'A' && c <= 'Z' && opts->conversion == 's')
+ return -EINVAL;
if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
/* 0xE5 is legal as a first character, but we must substitute 0x05 */
/* because 0xE5 marks deleted files. Yes, DOS really does this. */
@@ -90,7 +88,7 @@ static int msdos_format_name(char conv,const char *name,int len,
*walk = (c >= 'a' && c <= 'z') ? c-32 : c;
}
if (space) return -EINVAL;
- if (conv == 's' && len && c != '.') {
+ if (opts->conversion == 's' && len && c != '.') {
c = *name++;
len--;
if (c != '.') return -EINVAL;
@@ -101,26 +99,31 @@ static int msdos_format_name(char conv,const char *name,int len,
while (len > 0 && walk-res < MSDOS_NAME) {
c = *name++;
len--;
- if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
- if (conv == 's' && strchr(bad_if_strict,c))
+ if (opts->conversion != 'r' && strchr(bad_chars,c))
+ return -EINVAL;
+ if (opts->conversion == 's' &&
+ strchr(bad_if_strict(opts),c))
return -EINVAL;
if (c < ' ' || c == ':' || c == '\\')
return -EINVAL;
if (c == '.') {
- if (conv == 's')
+ if (opts->conversion == 's')
return -EINVAL;
break;
}
- if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
+ if (c >= 'A' && c <= 'Z' && opts->conversion == 's')
+ return -EINVAL;
space = c == ' ';
*walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
}
if (space) return -EINVAL;
- if (conv == 's' && len) return -EINVAL;
+ if (opts->conversion == 's' && len) return -EINVAL;
}
while (walk-res < MSDOS_NAME) *walk++ = ' ';
- for (reserved = reserved_names; *reserved; reserved++)
- if (!strncmp(res,*reserved,8)) return -EINVAL;
+ if (!opts->atari)
+ /* GEMDOS is less stupid and has no reserved names */
+ for (reserved = reserved_names; *reserved; reserved++)
+ if (!strncmp(res,*reserved,8)) return -EINVAL;
return 0;
}
@@ -133,8 +136,7 @@ static int msdos_find(struct inode *dir,const char *name,int len,
char msdos_name[MSDOS_NAME];
dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK;
- res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
- name,len, msdos_name,dotsOK);
+ res = msdos_format_name(name,len, msdos_name,&MSDOS_SB(dir->i_sb)->options);
if (res < 0)
return -ENOENT;
res = fat_scan(dir,msdos_name,bh,de,ino);
@@ -163,8 +165,7 @@ static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
int error;
char msdos_name[MSDOS_NAME];
- error = msdos_format_name(options->name_check, qstr->name, qstr->len,
- msdos_name, options->dotsOK);
+ error = msdos_format_name(qstr->name, qstr->len, msdos_name, options);
if (!error)
qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
return 0;
@@ -180,12 +181,10 @@ static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
int error;
char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
- error = msdos_format_name(options->name_check, a->name, a->len,
- a_msdos_name, options->dotsOK);
+ error = msdos_format_name(a->name, a->len, a_msdos_name, options);
if (error)
goto old_compare;
- error = msdos_format_name(options->name_check, b->name, b->len,
- b_msdos_name, options->dotsOK);
+ error = msdos_format_name(b->name, b->len, b_msdos_name, options);
if (error)
goto old_compare;
error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
@@ -288,9 +287,8 @@ int msdos_create(struct inode *dir,struct dentry *dentry,int mode)
int ino,res,is_hid;
char msdos_name[MSDOS_NAME];
- res = msdos_format_name(MSDOS_SB(sb)->options.name_check,
- dentry->d_name.name,dentry->d_name.len,
- msdos_name, MSDOS_SB(sb)->options.dotsOK);
+ res = msdos_format_name(dentry->d_name.name,dentry->d_name.len,
+ msdos_name, &MSDOS_SB(sb)->options);
if (res < 0)
return res;
is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
@@ -363,13 +361,10 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
struct inode *inode;
int res,is_hid;
char msdos_name[MSDOS_NAME];
- struct buffer_head *bh1;
- struct msdos_dir_entry *de1;
int ino;
- res = msdos_format_name(MSDOS_SB(sb)->options.name_check,
- dentry->d_name.name,dentry->d_name.len,
- msdos_name,MSDOS_SB(sb)->options.dotsOK);
+ res = msdos_format_name(dentry->d_name.name,dentry->d_name.len,
+ msdos_name, &MSDOS_SB(sb)->options);
if (res < 0)
return res;
is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
@@ -385,41 +380,16 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
fat_brelse(sb, bh);
goto out_unlock;
}
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty(inode);
res = 0;
dir->i_nlink++;
inode->i_nlink = 2; /* no need to mark them dirty */
- if (!(bh1 = fat_add_cluster1(inode))) {
- res = -ENOSPC;
+ res = fat_new_dir(inode, dir, 0);
+ if (res)
goto mkdir_error;
- }
- fat_brelse(sb, bh);
- de1 = (struct msdos_dir_entry *)bh1->b_data;
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- mark_inode_dirty(inode);
- memcpy(de1->name,MSDOS_DOT,MSDOS_NAME);
- de1->attr = ATTR_DIR;
- de1->start = CT_LE_W(MSDOS_I(inode)->i_logstart);
- de1->starthi = CT_LE_W(MSDOS_I(inode)->i_logstart >> 16);
- fat_date_unix2dos(inode->i_mtime,&de1->time,&de1->date);
- de1->size = 0;
- de1->time = CT_LE_W(de1->time);
- de1->date = CT_LE_W(de1->date);
- de1++;
- memcpy(de1->name,MSDOS_DOTDOT,MSDOS_NAME);
- de1->attr = ATTR_DIR;
- de1->start = CT_LE_W(MSDOS_I(dir)->i_logstart);
- de1->starthi = CT_LE_W(MSDOS_I(dir)->i_logstart >> 16);
- fat_date_unix2dos(dir->i_mtime,&de1->time,&de1->date);
- de1->size = 0;
- de1->time = CT_LE_W(de1->time);
- de1->date = CT_LE_W(de1->date);
- fat_mark_buffer_dirty(sb, bh1, 1);
- fat_brelse(sb, bh1);
+ fat_brelse(sb, bh);
d_instantiate(dentry, inode);
res = 0;
@@ -586,14 +556,14 @@ int msdos_rename(struct inode *old_dir,struct dentry *old_dentry,
int is_hid,old_hid; /* if new file and old file are hidden */
char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
- error = msdos_format_name(MSDOS_SB(sb)->options.name_check,
- old_dentry->d_name.name, old_dentry->d_name.len,
- old_msdos_name,MSDOS_SB(sb)->options.dotsOK);
+ error = msdos_format_name(old_dentry->d_name.name,
+ old_dentry->d_name.len,old_msdos_name,
+ &MSDOS_SB(old_dir->i_sb)->options);
if (error < 0)
goto rename_done;
- error = msdos_format_name(MSDOS_SB(sb)->options.name_check,
- new_dentry->d_name.name, new_dentry->d_name.len,
- new_msdos_name,MSDOS_SB(sb)->options.dotsOK);
+ error = msdos_format_name(new_dentry->d_name.name,
+ new_dentry->d_name.len,new_msdos_name,
+ &MSDOS_SB(new_dir->i_sb)->options);
if (error < 0)
goto rename_done;
diff --git a/fs/namei.c b/fs/namei.c
index e39cd24e1..9191689b2 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -250,7 +250,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, i
* FIXME! This could use version numbering or similar to
* avoid unnecessary cache lookups.
*/
- result = cached_lookup(parent, name, flags);
+ result = d_lookup(parent, name);
if (!result) {
struct dentry * dentry = d_alloc(parent, name);
result = ERR_PTR(-ENOMEM);
@@ -261,8 +261,19 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, i
else
result = dentry;
}
+ up(&dir->i_sem);
+ return result;
}
+
+ /*
+ * Uhhuh! Nasty case: the cache was re-populated while
+ * we waited on the semaphore. Need to revalidate, but
+ * we're going to return this entry regardless (same
+ * as if it was busy).
+ */
up(&dir->i_sem);
+ if (result->d_op && result->d_op->d_revalidate)
+ result->d_op->d_revalidate(result, flags);
return result;
}
@@ -838,7 +849,7 @@ exit_lock:
return retval;
}
-asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
+asmlinkage long sys_mknod(const char * filename, int mode, dev_t dev)
{
int error;
char * tmp;
@@ -929,7 +940,7 @@ exit:
return error;
}
-asmlinkage int sys_mkdir(const char * pathname, int mode)
+asmlinkage long sys_mkdir(const char * pathname, int mode)
{
int error;
char * tmp;
@@ -1024,7 +1035,7 @@ exit:
return error;
}
-asmlinkage int sys_rmdir(const char * pathname)
+asmlinkage long sys_rmdir(const char * pathname)
{
int error;
char * tmp;
@@ -1077,7 +1088,7 @@ exit:
return error;
}
-asmlinkage int sys_unlink(const char * pathname)
+asmlinkage long sys_unlink(const char * pathname)
{
int error;
char * tmp;
@@ -1128,7 +1139,7 @@ exit:
return error;
}
-asmlinkage int sys_symlink(const char * oldname, const char * newname)
+asmlinkage long sys_symlink(const char * oldname, const char * newname)
{
int error;
char * from;
@@ -1216,7 +1227,7 @@ exit:
return error;
}
-asmlinkage int sys_link(const char * oldname, const char * newname)
+asmlinkage long sys_link(const char * oldname, const char * newname)
{
int error;
char * from;
@@ -1387,7 +1398,7 @@ exit:
return error;
}
-asmlinkage int sys_rename(const char * oldname, const char * newname)
+asmlinkage long sys_rename(const char * oldname, const char * newname)
{
int error;
char * from;
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index cf4c13fde..ee2886228 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -349,6 +349,9 @@ ncp_lookup_validate(struct dentry * dentry, int flags)
int len = dentry->d_name.len;
struct ncpfs_inode_info finfo;
__u8 __name[dentry->d_name.len + 1];
+
+ if (!dentry->d_inode || !dir)
+ return 0;
server = NCP_SERVER(dir);
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 36f37c232..88d56f7b2 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -134,7 +134,15 @@ void ncp_update_inode2(struct inode* inode, struct nw_file_info *nwinfo)
if ((inode->i_size)&&(inode->i_blksize)) {
inode->i_blocks = (inode->i_size-1)/(inode->i_blksize)+1;
}
+
/* TODO: times? I'm not sure... */
+ inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwinfo->i.modifyTime),
+ le16_to_cpu(nwinfo->i.modifyDate));
+ inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwinfo->i.creationTime),
+ le16_to_cpu(nwinfo->i.creationDate));
+ inode->i_atime = ncp_date_dos2unix(0,
+ le16_to_cpu(nwinfo->i.lastAccessDate));
+
NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber;
@@ -712,7 +720,7 @@ static struct file_system_type ncp_fs_type = {
NULL
};
-__initfunc(int init_ncp_fs(void))
+int __init init_ncp_fs(void)
{
return register_filesystem(&ncp_fs_type);
}
diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c
index 0a293ca85..81ac20840 100644
--- a/fs/ncpfs/sock.c
+++ b/fs/ncpfs/sock.c
@@ -172,8 +172,11 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size,
re_select:
wait_table.nr = 0;
wait_table.entry = &entry;
- current->state = TASK_INTERRUPTIBLE;
- if (!(file->f_op->poll(file, &wait_table) & POLLIN)) {
+ /* mb() is not necessary because ->poll() will serialize
+ instructions adding the wait_table waitqueues in the
+ waitqueue-head before going to calculate the mask-retval. */
+ __set_current_state(TASK_INTERRUPTIBLE);
+ if (!(sock->ops->poll(file, sock, &wait_table) & POLLIN)) {
int timed_out;
if (timeout > max_timeout) {
/* JEJB/JSP 2/7/94
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 31d76e5c6..6b52b2d54 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -601,6 +601,8 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
/* Filehandle matches? */
if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) {
+ if (!list_empty(&dentry->d_subdirs))
+ shrink_dcache_parent(dentry);
if (dentry->d_count < 2)
goto out_bad;
}
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 65d3f76a2..d9a423f16 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -154,7 +154,7 @@ static struct nfs_bool_opts {
* need to have root_server_addr set _before_ IPConfig gets called as it
* can override it.
*/
-__initfunc(static void root_nfs_parse_addr(char *name))
+static void __init root_nfs_parse_addr(char *name)
{
int octets = 0;
char *cp, *cq;
@@ -183,7 +183,7 @@ __initfunc(static void root_nfs_parse_addr(char *name))
/*
* Parse option string.
*/
-__initfunc(static void root_nfs_parse(char *name, char *buf))
+static void __init root_nfs_parse(char *name, char *buf)
{
char *options, *val, *cp;
@@ -220,7 +220,7 @@ __initfunc(static void root_nfs_parse(char *name, char *buf))
/*
* Prepare the NFS data structure and parse all options.
*/
-__initfunc(static int root_nfs_name(char *name))
+static int __init root_nfs_name(char *name)
{
char buf[NFS_MAXPATHLEN];
char *cp;
@@ -261,7 +261,7 @@ __initfunc(static int root_nfs_name(char *name))
/*
* Get NFS server address.
*/
-__initfunc(static int root_nfs_addr(void))
+static int __init root_nfs_addr(void)
{
if ((servaddr = root_server_addr) == INADDR_NONE) {
printk(KERN_ERR "Root-NFS: No NFS server available, giving up.\n");
@@ -277,7 +277,7 @@ __initfunc(static int root_nfs_addr(void))
* Tell the user what's going on.
*/
#ifdef NFSROOT_DEBUG
-__initfunc(static void root_nfs_print(void))
+static void __init root_nfs_print(void)
{
printk(KERN_NOTICE "Root-NFS: Mounting %s on server %s as root\n",
nfs_path, nfs_data.hostname);
@@ -292,7 +292,7 @@ __initfunc(static void root_nfs_print(void))
#endif
-__initfunc(int root_nfs_init(void))
+int __init root_nfs_init(void)
{
#ifdef NFSROOT_DEBUG
nfs_debug |= NFSDBG_ROOT;
@@ -320,7 +320,7 @@ __initfunc(int root_nfs_init(void))
* Parse NFS server and directory information passed on the kernel
* command line.
*/
-__initfunc(void nfs_root_setup(char *line, int *ints))
+void __init nfs_root_setup(char *line)
{
ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);
if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
@@ -335,6 +335,7 @@ __initfunc(void nfs_root_setup(char *line, int *ints))
root_nfs_parse_addr(nfs_root_name);
}
+__setup("nfsroot=", nfs_root_setup);
/***************************************************************************
@@ -356,7 +357,7 @@ set_sockaddr(struct sockaddr_in *sin, __u32 addr, __u16 port)
/*
* Query server portmapper for the port of a daemon program.
*/
-__initfunc(static int root_nfs_getport(int program, int version))
+static int __init root_nfs_getport(int program, int version)
{
struct sockaddr_in sin;
@@ -372,7 +373,7 @@ __initfunc(static int root_nfs_getport(int program, int version))
* by the user. Use defaults if portmapper is not available.
* XXX: Is there any nfs server with no portmapper?
*/
-__initfunc(static int root_nfs_ports(void))
+static int __init root_nfs_ports(void)
{
int port;
@@ -403,7 +404,7 @@ __initfunc(static int root_nfs_ports(void))
* Get a file handle from the server for the directory which is to be
* mounted.
*/
-__initfunc(static int root_nfs_get_handle(void))
+static int __init root_nfs_get_handle(void)
{
struct sockaddr_in sin;
int status;
@@ -421,7 +422,7 @@ __initfunc(static int root_nfs_get_handle(void))
/*
* Now actually mount the given directory.
*/
-__initfunc(static int root_nfs_do_mount(struct super_block *sb))
+static int __init root_nfs_do_mount(struct super_block *sb)
{
/* Pass the server address to NFS */
set_sockaddr((struct sockaddr_in *) &nfs_data.addr, servaddr, nfs_port);
@@ -437,7 +438,7 @@ __initfunc(static int root_nfs_do_mount(struct super_block *sb))
* Get the NFS port numbers and file handle, and then read the super-
* block for mounting.
*/
-__initfunc(int nfs_root_mount(struct super_block *sb))
+int __init nfs_root_mount(struct super_block *sb)
{
if (root_nfs_init() < 0
|| root_nfs_ports() < 0
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 899b62c82..a7960c1e0 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -152,7 +152,7 @@ nfs_readpage_result(struct rpc_task *task)
fail++;
dprintk("NFS: %d successful reads, %d failures\n", succ, fail);
}
- page->owner = (int)current; // HACK, FIXME, will go away.
+ page->owner = current; // HACK, FIXME, will go away.
UnlockPage(page);
free_page(address);
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 77c1db091..561e8450c 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -392,7 +392,7 @@ wait_on_write_request(struct nfs_wreq *req)
rpc_clnt_sigmask(clnt, &oldmask);
add_wait_queue(&req->wb_wait, &wait);
for (;;) {
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
retval = 0;
if (req->wb_flags & NFS_WRITE_COMPLETE)
break;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 14cb7d50f..999d90d25 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -995,12 +995,15 @@ out_nfserr:
* that the parent is still our parent and
* that we are still hashed onto it..
*
- * This is requied in case two processes race
+ * This is required in case two processes race
* on removing (or moving) the same entry: the
* parent lock will serialize them, but the
* other process will be too late..
+ *
+ * Note that this nfsd_check_parent is different
+ * than the one in linux/include/dcache_func.h.
*/
-#define check_parent(dir, dentry) \
+#define nfsd_check_parent(dir, dentry) \
((dir) == (dentry)->d_parent->d_inode && !list_empty(&dentry->d_hash))
/*
@@ -1079,8 +1082,8 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
nfsd_double_down(&tdir->i_sem, &fdir->i_sem);
err = -ENOENT;
/* GAM3 check for parent changes after locking. */
- if (check_parent(fdir, odentry) &&
- check_parent(tdir, ndentry)) {
+ if (nfsd_check_parent(fdir, odentry) &&
+ nfsd_check_parent(tdir, ndentry)) {
err = vfs_rename(fdir, odentry, tdir, ndentry);
if (!err && EX_ISSYNC(tfhp->fh_export)) {
@@ -1168,7 +1171,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
fhp->fh_locked = 1;
err = -ENOENT;
- if (check_parent(dirp, rdentry))
+ if (nfsd_check_parent(dirp, rdentry))
err = vfs_rmdir(dirp, rdentry);
rdentry->d_count--;
diff --git a/fs/nls/Config.in b/fs/nls/Config.in
index 7e591b82a..7d86a4091 100644
--- a/fs/nls/Config.in
+++ b/fs/nls/Config.in
@@ -38,6 +38,7 @@ if [ "$CONFIG_NLS" = "y" ]; then
tristate 'NLS ISO 8859-7 (Modern Greek)' CONFIG_NLS_ISO8859_7
tristate 'NLS ISO 8859-8 (Hebrew)' CONFIG_NLS_ISO8859_8
tristate 'NLS ISO 8859-9 (Latin 5; Turkish)' CONFIG_NLS_ISO8859_9
+ tristate 'NLS ISO 8859-14 (Latin 8; Celtic)' CONFIG_NLS_ISO8859_14
tristate 'NLS ISO 8859-15 (Latin 9; Western European Languages with Euro)' CONFIG_NLS_ISO8859_15
tristate 'NLS KOI8-R (Russian)' CONFIG_NLS_KOI8_R
endmenu
diff --git a/fs/nls/Makefile b/fs/nls/Makefile
index 879fef8ff..3d7688f0d 100644
--- a/fs/nls/Makefile
+++ b/fs/nls/Makefile
@@ -286,6 +286,14 @@ else
endif
endif
+ifeq ($(CONFIG_NLS_ISO8859_14),y)
+NLS += nls_iso8859-14.o
+else
+ ifeq ($(CONFIG_NLS_ISO8859_14),m)
+ M_OBJS += nls_iso8859-14.o
+ endif
+endif
+
ifeq ($(CONFIG_NLS_ISO8859_15),y)
NLS += nls_iso8859-15.o
else
diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
index b6483a1d6..40d5d6c2c 100644
--- a/fs/nls/nls_base.c
+++ b/fs/nls/nls_base.c
@@ -429,6 +429,9 @@ int init_nls(void)
#ifdef CONFIG_NLS_ISO8859_9
init_nls_iso8859_9();
#endif
+#ifdef CONFIG_NLS_ISO8859_14
+ init_nls_iso8859_14();
+#endif
#ifdef CONFIG_NLS_ISO8859_15
init_nls_iso8859_15();
#endif
diff --git a/fs/nls/nls_iso8859-14.c b/fs/nls/nls_iso8859-14.c
new file mode 100644
index 000000000..b466a6560
--- /dev/null
+++ b/fs/nls/nls_iso8859-14.c
@@ -0,0 +1,275 @@
+/*
+ * linux/fs/nls_iso8859-14.c
+ *
+ * Charset iso8859-14 translation tables.
+ *
+ * Generated automatically from the Unicode and charset table
+ * provided by the Unicode Organisation at
+ * http://www.unicode.org/
+ * The Unicode to charset table has only exact mappings.
+ *
+ * Rhys Jones, Swansea University Computer Society
+ * rhys@sucs.swan.ac.uk
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0x90*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xa0*/
+ {0xa0, 0x00}, {0x02, 0x1e}, {0x03, 0x1e}, {0xa3, 0x00},
+ {0x0a, 0x01}, {0x0b, 0x01}, {0x0a, 0x1e}, {0xa7, 0x00},
+ {0x80, 0x1e}, {0xa9, 0x00}, {0x82, 0x1e}, {0x0b, 0x1e},
+ {0xf2, 0x1e}, {0xad, 0x00}, {0xae, 0x00}, {0x78, 0x01},
+ /* 0xb0*/
+ {0x1e, 0x1e}, {0x1f, 0x1e}, {0x20, 0x01}, {0x21, 0x01},
+ {0x40, 0x1e}, {0x41, 0x1e}, {0xb6, 0x00}, {0x56, 0x1e},
+ {0x81, 0x1e}, {0x57, 0x1e}, {0x83, 0x1e}, {0x60, 0x1e},
+ {0xf3, 0x1e}, {0x84, 0x1e}, {0x85, 0x1e}, {0x61, 0x1e},
+ /* 0xc0*/
+ {0xc0, 0x00}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc3, 0x00},
+ {0xc4, 0x00}, {0xc5, 0x00}, {0xc6, 0x00}, {0xc7, 0x00},
+ {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+ {0xcc, 0x00}, {0xcd, 0x00}, {0xce, 0x00}, {0xcf, 0x00},
+ /* 0xd0*/
+ {0x74, 0x01}, {0xd1, 0x00}, {0xd2, 0x00}, {0xd3, 0x00},
+ {0xd4, 0x00}, {0xd5, 0x00}, {0xd6, 0x00}, {0x6a, 0x1e},
+ {0xd8, 0x00}, {0xd9, 0x00}, {0xda, 0x00}, {0xdb, 0x00},
+ {0xdc, 0x00}, {0xdd, 0x00}, {0x76, 0x01}, {0xdf, 0x00},
+ /* 0xe0*/
+ {0xe0, 0x00}, {0xe1, 0x00}, {0xe2, 0x00}, {0xe3, 0x00},
+ {0xe4, 0x00}, {0xe5, 0x00}, {0xe6, 0x00}, {0xe7, 0x00},
+ {0xe8, 0x00}, {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0x00},
+ {0xec, 0x00}, {0xed, 0x00}, {0xee, 0x00}, {0xef, 0x00},
+ /* 0xf0*/
+ {0x75, 0x01}, {0xf1, 0x00}, {0xf2, 0x00}, {0xf3, 0x00},
+ {0xf4, 0x00}, {0xf5, 0x00}, {0xf6, 0x00}, {0x6b, 0x1e},
+ {0xf8, 0x00}, {0xf9, 0x00}, {0xfa, 0x00}, {0xfb, 0x00},
+ {0xfc, 0x00}, {0xfd, 0x00}, {0x77, 0x01}, {0xff, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xa0, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */
+ 0x00, 0xa9, 0x00, 0x00, 0x00, 0xad, 0xae, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0x00, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0x00, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0x00, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0x00, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0x00, 0xff, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0x00, 0x00, 0xa1, 0xa2, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0xa6, 0xab, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb1, /* 0x18-0x1f */
+ 0xb2, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0xb4, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0xb9, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0xbb, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0xd7, 0xf7, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0xd0, 0xf0, 0xde, 0xfe, /* 0x70-0x77 */
+ 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xa8, 0xb8, 0xaa, 0xba, 0xbd, 0xbe, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page1e[256] = {
+ 0x00, 0x00, 0xa1, 0xa2, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0xa6, 0xab, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb1, /* 0x18-0x1f */
+ 0xb2, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0xb4, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0xb9, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0xbb, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0xd7, 0xf7, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0xd0, 0xf0, 0xde, 0xfe, /* 0x70-0x77 */
+ 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xa8, 0xb8, 0xaa, 0xba, 0xbd, 0xbe, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, page1e, NULL,
+
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "iso8859-14",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_iso8859_14(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_iso8859_14();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/noquot.c b/fs/noquot.c
index cd511fd36..bc8755ed6 100644
--- a/fs/noquot.c
+++ b/fs/noquot.c
@@ -9,7 +9,7 @@
int nr_dquots = 0, nr_free_dquots = 0;
int max_dquots = 0;
-asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
+asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
{
return(-ENOSYS);
}
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index cc6bfe2e3..4fe6df055 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -1028,10 +1028,10 @@ static struct file_system_type ntfs_fs_type = {
/* When this code is not compiled as a module, this is the main entry point,
* called by do_sys_setup() in fs/filesystems.c
*
- * NOTE : __initfunc() is a macro used to remove this function from memory
+ * NOTE : __init is a macro used to remove this function from memory
* once initialization is done
*/
-__initfunc(int init_ntfs_fs(void))
+int __init init_ntfs_fs(void)
{
/* Comment this if you trust klogd. There are reasons not to trust it
*/
diff --git a/fs/open.c b/fs/open.c
index c0f806f69..5a86dc48a 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -12,7 +12,7 @@
#include <asm/uaccess.h>
-asmlinkage int sys_statfs(const char * path, struct statfs * buf)
+asmlinkage long sys_statfs(const char * path, struct statfs * buf)
{
struct dentry * dentry;
int error;
@@ -34,7 +34,7 @@ asmlinkage int sys_statfs(const char * path, struct statfs * buf)
return error;
}
-asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
+asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf)
{
struct file * file;
struct super_block * sb;
@@ -79,7 +79,7 @@ int do_truncate(struct dentry *dentry, unsigned long length)
return error;
}
-asmlinkage int sys_truncate(const char * path, unsigned long length)
+asmlinkage long sys_truncate(const char * path, unsigned long length)
{
struct dentry * dentry;
struct inode * inode;
@@ -128,7 +128,7 @@ out:
return error;
}
-asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length)
+asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length)
{
struct inode * inode;
struct dentry *dentry;
@@ -176,7 +176,7 @@ out:
* must be owner or have write permission.
* Else, update from *times, must be owner or super user.
*/
-asmlinkage int sys_utime(char * filename, struct utimbuf * times)
+asmlinkage long sys_utime(char * filename, struct utimbuf * times)
{
int error;
struct dentry * dentry;
@@ -224,7 +224,7 @@ out:
* must be owner or have write permission.
* Else, update from *times, must be owner or super user.
*/
-asmlinkage int sys_utimes(char * filename, struct timeval * utimes)
+asmlinkage long sys_utimes(char * filename, struct timeval * utimes)
{
int error;
struct dentry * dentry;
@@ -270,7 +270,7 @@ out:
* We do this by temporarily clearing all FS-related capabilities and
* switching the fsuid/fsgid around to the real ones.
*/
-asmlinkage int sys_access(const char * filename, int mode)
+asmlinkage long sys_access(const char * filename, int mode)
{
struct dentry * dentry;
int old_fsuid, old_fsgid;
@@ -311,7 +311,7 @@ out:
return res;
}
-asmlinkage int sys_chdir(const char * filename)
+asmlinkage long sys_chdir(const char * filename)
{
int error;
struct inode *inode;
@@ -346,7 +346,7 @@ out:
return error;
}
-asmlinkage int sys_fchdir(unsigned int fd)
+asmlinkage long sys_fchdir(unsigned int fd)
{
struct file *file;
struct dentry *dentry;
@@ -382,7 +382,7 @@ out:
return error;
}
-asmlinkage int sys_chroot(const char * filename)
+asmlinkage long sys_chroot(const char * filename)
{
int error;
struct inode *inode;
@@ -422,7 +422,7 @@ out:
return error;
}
-asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
+asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
{
struct inode * inode;
struct dentry * dentry;
@@ -460,7 +460,7 @@ out:
return err;
}
-asmlinkage int sys_chmod(const char * filename, mode_t mode)
+asmlinkage long sys_chmod(const char * filename, mode_t mode)
{
struct dentry * dentry;
struct inode * inode;
@@ -551,7 +551,7 @@ out:
return error;
}
-asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
+asmlinkage long sys_chown(const char * filename, uid_t user, gid_t group)
{
struct dentry * dentry;
int error;
@@ -568,7 +568,7 @@ asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
return error;
}
-asmlinkage int sys_lchown(const char * filename, uid_t user, gid_t group)
+asmlinkage long sys_lchown(const char * filename, uid_t user, gid_t group)
{
struct dentry * dentry;
int error;
@@ -586,7 +586,7 @@ asmlinkage int sys_lchown(const char * filename, uid_t user, gid_t group)
}
-asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
+asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
{
struct dentry * dentry;
struct file * file;
@@ -685,10 +685,14 @@ int get_unused_fd(void)
struct files_struct * files = current->files;
int fd, error;
- error = -EMFILE;
-
+ error = -EMFILE;
write_lock(&files->file_lock);
- fd = find_first_zero_bit(&files->open_fds, NR_OPEN);
+
+repeat:
+ fd = find_next_zero_bit(files->open_fds,
+ current->files->max_fdset,
+ files->next_fd);
+
/*
* N.B. For clone tasks sharing a files structure, this test
* will limit the total number of files that can be opened.
@@ -696,10 +700,31 @@ int get_unused_fd(void)
if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur)
goto out;
- /* Check here for fd > files->max_fds to do dynamic expansion */
+ /* Do we need to expand the fdset array? */
+ if (fd >= current->files->max_fdset) {
+ error = expand_fdset(files, 0);
+ if (!error) {
+ error = -EMFILE;
+ goto repeat;
+ }
+ goto out;
+ }
+
+ /*
+ * Check whether we need to expand the fd array.
+ */
+ if (fd >= files->max_fds) {
+ error = expand_fd_array(files, 0);
+ if (!error) {
+ error = -EMFILE;
+ goto repeat;
+ }
+ goto out;
+ }
- FD_SET(fd, &files->open_fds);
- FD_CLR(fd, &files->close_on_exec);
+ FD_SET(fd, files->open_fds);
+ FD_CLR(fd, files->close_on_exec);
+ files->next_fd = fd + 1;
#if 1
/* Sanity check */
if (files->fd[fd] != NULL) {
@@ -717,11 +742,13 @@ out:
inline void put_unused_fd(unsigned int fd)
{
write_lock(&current->files->file_lock);
- FD_CLR(fd, &current->files->open_fds);
+ FD_CLR(fd, current->files->open_fds);
+ if (fd < current->files->next_fd)
+ current->files->next_fd = fd;
write_unlock(&current->files->file_lock);
}
-asmlinkage int sys_open(const char * filename, int flags, int mode)
+asmlinkage long sys_open(const char * filename, int flags, int mode)
{
char * tmp;
int fd, error;
@@ -757,7 +784,7 @@ out_error:
* For backward compatibility? Maybe this should be moved
* into arch/i386 instead?
*/
-asmlinkage int sys_creat(const char * pathname, int mode)
+asmlinkage long sys_creat(const char * pathname, int mode)
{
return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
}
@@ -765,22 +792,6 @@ asmlinkage int sys_creat(const char * pathname, int mode)
#endif
/*
- * Called when retiring the last use of a file pointer.
- */
-void __fput(struct file *filp)
-{
- struct dentry * dentry = filp->f_dentry;
- struct inode * inode = dentry->d_inode;
-
- if (filp->f_op && filp->f_op->release)
- filp->f_op->release(inode, filp);
- filp->f_dentry = NULL;
- if (filp->f_mode & FMODE_WRITE)
- put_write_access(inode);
- dput(dentry);
-}
-
-/*
* "id" is the POSIX thread ID. We use the
* files pointer for this..
*/
@@ -806,8 +817,12 @@ int filp_close(struct file *filp, fl_owner_t id)
* Careful here! We test whether the file pointer is NULL before
* releasing the fd. This ensures that one clone task can't release
* an fd while another clone is opening it.
+ *
+ * The "release" argument tells us whether or not to mark the fd as free
+ * or not in the open-files bitmap. dup2 uses this to retain the fd
+ * without races.
*/
-asmlinkage int sys_close(unsigned int fd)
+int do_close(unsigned int fd, int release)
{
int error;
struct file * filp;
@@ -818,9 +833,10 @@ asmlinkage int sys_close(unsigned int fd)
filp = frip(fd);
if (!filp)
goto out_unlock;
- FD_CLR(fd, &files->close_on_exec);
+ FD_CLR(fd, files->close_on_exec);
write_unlock(&files->file_lock);
- put_unused_fd(fd);
+ if (release)
+ put_unused_fd(fd);
lock_kernel();
error = filp_close(filp, files);
unlock_kernel();
@@ -831,11 +847,16 @@ out_unlock:
goto out;
}
+asmlinkage long sys_close(unsigned int fd)
+{
+ return do_close(fd, 1);
+}
+
/*
* This routine simulates a hangup on the tty, to arrange that users
* are given clean terminals at login time.
*/
-asmlinkage int sys_vhangup(void)
+asmlinkage long sys_vhangup(void)
{
int ret = -EPERM;
diff --git a/fs/partitions/.cvsignore b/fs/partitions/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/fs/partitions/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/fs/partitions/Config.in b/fs/partitions/Config.in
new file mode 100644
index 000000000..31e5884f4
--- /dev/null
+++ b/fs/partitions/Config.in
@@ -0,0 +1,67 @@
+#
+# Partition configuration
+#
+bool 'Advanced partition selection' CONFIG_PARTITION_ADVANCED
+if [ "$CONFIG_PARTITION_ADVANCED" = "y" ]; then
+ bool 'Alpha OSF partition support' CONFIG_OSF_PARTITION
+ bool 'Macintosh partition map support' CONFIG_MAC_PARTITION
+ bool 'PC BIOS (MSDOS partition tables) support' CONFIG_MSDOS_PARTITION
+else
+ if [ "$ARCH" = "alpha" ]; then
+ define_bool CONFIG_OSF_PARTITION y
+ fi
+ if [ "$ARCH" = "ppc" -o "$CONFIG_MAC" = "y" ]; then
+ define_bool CONFIG_MAC_PARTITION y
+ fi
+ if [ "$CONFIG_AMIGA" != "y" -a "$CONFIG_ATARI" != "y" -a \
+ "$CONFIG_MAC" != "y" ]; then
+ define_bool CONFIG_MSDOS_PARTITION y
+ fi
+fi
+if [ "$CONFIG_MSDOS_PARTITION" = "y" ]; then
+ bool ' BSD disklabel (FreeBSD partition tables) support' CONFIG_BSD_DISKLABEL
+ bool ' Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
+ bool ' Unixware slices support' CONFIG_UNIXWARE_DISKLABEL
+fi
+if [ "$CONFIG_SGI_IP22" != "y" ]; then
+ bool 'SGI partition support' CONFIG_SGI_PARTITION
+else
+ define_bool CONFIG_SGI_PARTITION y
+fi
+if [ "$CONFIG_DECSTATION" != "y" ]; then
+ bool 'Ultrix partition table support' CONFIG_ULTRIX_PARTITION
+else
+ define_bool CONFIG_ULTRIX_PARTITION y
+fi
+if [ "$ARCH" != "sparc" -a "$ARCH" != "sparc64" ]; then
+ bool 'Sun partition tables support' CONFIG_SUN_PARTITION
+else
+ define_bool CONFIG_SUN_PARTITION y
+fi
+if [ "$CONFIG_PARTITION_ADVANCED" = "y" ]; then
+ bool 'Amiga partition table support' CONFIG_AMIGA_PARTITION
+ bool 'Atari partition table support' CONFIG_ATARI_PARTITION
+ bool 'Acorn partition support' CONFIG_ACORN_PARTITION
+ if [ "$CONFIG_ACORN_PARTITION" != "n" ]; then
+ bool ' Native filecore partition support' CONFIG_ACORN_PARTITION_ADFS
+# bool ' Cumana partition support' CONFIG_ACORN_PARTITION_CUMANA
+ bool ' ICS partition support' CONFIG_ACORN_PARTITION_ICS
+ bool ' PowerTec partition support' CONFIG_ACORN_PARTITION_POWERTEC
+ bool ' RISCiX partition support' CONFIG_ACORN_PARTITION_RISCIX
+ fi
+else
+ if [ "$CONFIG_AMIGA" = "y" ]; then
+ define_bool CONFIG_AMIGA_PARTITION y
+ fi
+ if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+ define_bool CONFIG_ACORN_PARTITION y
+ define_bool CONFIG_ACORN_PARTITION_ADFS y
+# define_bool CONFIG_ACORN_PARTITION_CUMANA y
+ define_bool CONFIG_ACORN_PARTITION_ICS y
+ define_bool CONFIG_ACORN_PARTITION_POWERTEC y
+ define_bool CONFIG_ACORN_PARTITION_RISCIX y
+ fi
+fi
+if [ "$CONFIG_ATARI" = "y" ]; then
+ define_bool CONFIG_ATARI_PARTITION y
+fi
diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile
new file mode 100644
index 000000000..2dc58c20d
--- /dev/null
+++ b/fs/partitions/Makefile
@@ -0,0 +1,49 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := partitions.o
+O_OBJS := check.o
+
+ifeq ($(CONFIG_ACORN_PARTITION),y)
+O_OBJS += acorn.o
+endif
+
+ifeq ($(CONFIG_AMIGA_PARTITION),y)
+O_OBJS += amiga.o
+endif
+
+ifeq ($(CONFIG_ATARI_PARTITION),y)
+O_OBJS += atari.o
+endif
+
+ifeq ($(CONFIG_MAC_PARTITION),y)
+O_OBJS += mac.o
+endif
+
+ifeq ($(CONFIG_MSDOS_PARTITION),y)
+O_OBJS += msdos.o
+endif
+
+ifeq ($(CONFIG_OSF_PARTITION),y)
+O_OBJS += osf.o
+endif
+
+ifeq ($(CONFIG_SGI_PARTITION),y)
+O_OBJS += sgi.o
+endif
+
+ifeq ($(CONFIG_SUN_PARTITION),y)
+O_OBJS += sun.o
+endif
+
+ifeq ($(CONFIG_ULTRIX_PARTITION),y)
+O_OBJS += ultrix.o
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c
new file mode 100644
index 000000000..bce1d34aa
--- /dev/null
+++ b/fs/partitions/acorn.c
@@ -0,0 +1,472 @@
+/*
+ * linux/arch/arm/drivers/block/adfspart.c
+ *
+ * Copyright (c) 1996,1997 Russell King.
+ *
+ * Scan ADFS partitions on hard disk drives.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/genhd.h>
+#include <linux/fs.h>
+
+#include "acorn.h"
+
+extern void add_gd_partition(struct gendisk *hd, unsigned int minor, unsigned int start, unsigned int size);
+
+static void
+adfspart_setgeometry(kdev_t dev, unsigned int secspertrack, unsigned int heads,
+ unsigned long totalblocks)
+{
+ extern void xd_set_geometry(kdev_t dev, unsigned char, unsigned char,
+ unsigned long, unsigned int);
+
+#ifdef CONFIG_BLK_DEV_MFM
+ if (MAJOR(dev) == MFM_ACORN_MAJOR)
+ xd_set_geometry(dev, secspertrack, heads, totalblocks, 1);
+#endif
+}
+
+#define LINUX_NATIVE_MAGIC 0xdeafa1de
+#define LINUX_SWAP_MAGIC 0xdeafab1e
+
+struct linux_part {
+ unsigned long magic;
+ unsigned long start_sect;
+ unsigned long nr_sects;
+};
+
+static struct disc_record *adfs_partition(struct gendisk *hd, char *name, char *data,
+ unsigned long first_sector, unsigned int minor)
+{
+ struct disc_record *dr;
+ unsigned int nr_sects;
+
+ if (adfs_checkbblk(data))
+ return NULL;
+
+ dr = (struct disc_record *)(data + 0x1c0);
+
+ if (dr->disc_size == 0 && dr->disc_size_high == 0)
+ return NULL;
+
+ nr_sects = (dr->disc_size_high << 23) | (dr->disc_size >> 9);
+
+ if (name)
+ printk(" [%s]", name);
+ add_gd_partition(hd, minor, first_sector, nr_sects);
+ return dr;
+}
+
+#ifdef CONFIG_ACORN_PARTITION_RISCIX
+static int riscix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sect,
+ unsigned int minor, unsigned long nr_sects)
+{
+ struct buffer_head *bh;
+ struct riscix_record *rr;
+ unsigned int riscix_minor;
+
+ if(get_ptable_blocksize(dev)!=1024)
+ return 0;
+
+ printk(" [RISCiX]");
+
+ add_gd_partition(hd, riscix_minor = minor++, first_sect, nr_sects);
+ hd->sizes[riscix_minor] = hd->part[riscix_minor].nr_sects >> (BLOCK_SIZE_BITS - 9);
+ dev = MKDEV(hd->major, riscix_minor);
+
+ if (!(bh = bread(dev, 0, 1024)))
+ return -1;
+
+ rr = (struct riscix_record *)bh->b_data;
+ if (rr->magic == RISCIX_MAGIC) {
+ int part;
+
+ printk(" <");
+
+ for (part = 0; part < 8; part++) {
+ if (rr->part[part].one &&
+ memcmp(rr->part[part].name, "All\0", 4)) {
+ add_gd_partition(hd, minor++,
+ rr->part[part].start,
+ rr->part[part].length);
+ printk("(%s)", rr->part[part].name);
+ }
+ }
+
+ printk(" >");
+
+ if (hd->part[riscix_minor].nr_sects > 2)
+ hd->part[riscix_minor].nr_sects = 2;
+ }
+
+ brelse(bh);
+ return minor;
+}
+#endif
+
+static int linux_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sect,
+ unsigned int minor, unsigned long nr_sects)
+{
+ struct buffer_head *bh;
+ struct linux_part *linuxp;
+ unsigned int linux_minor, mask = (1 << hd->minor_shift) - 1;
+
+ if(get_ptable_blocksize(dev)!=1024)
+ return 0;
+
+ printk(" [Linux]");
+
+ add_gd_partition(hd, linux_minor = minor++, first_sect, nr_sects);
+ hd->sizes[linux_minor] = hd->part[linux_minor].nr_sects >> (BLOCK_SIZE_BITS - 9);
+ dev = MKDEV(hd->major, linux_minor);
+
+ if (!(bh = bread(dev, 0, 1024)))
+ return -1;
+
+ linuxp = (struct linux_part *)bh->b_data;
+ printk(" <");
+ while (linuxp->magic == LINUX_NATIVE_MAGIC || linuxp->magic == LINUX_SWAP_MAGIC) {
+ if (!(minor & mask))
+ break;
+ add_gd_partition(hd, minor++, first_sect + linuxp->start_sect,
+ linuxp->nr_sects);
+ linuxp ++;
+ }
+ printk(" >");
+ /*
+ * Prevent someone doing a mkswap or mkfs on this partition
+ */
+ if(hd->part[linux_minor].nr_sects > 2)
+ hd->part[linux_minor].nr_sects = 2;
+
+ brelse(bh);
+ return minor;
+}
+
+#ifdef CONFIG_ACORN_PARTITION_CUMANA
+static int adfspart_check_CUMANA(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
+ unsigned int minor)
+{
+ unsigned int start_blk = 0, mask = (1 << hd->minor_shift) - 1;
+ struct buffer_head *bh = NULL;
+ char *name = "CUMANA/ADFS";
+ int first = 1;
+
+ if(get_ptable_blocksize(dev)!=1024)
+ return 0;
+
+ /*
+ * Try Cumana style partitions - sector 3 contains ADFS boot block with pointer
+ * to next 'drive'.
+ *
+ * There are unknowns in this code - is the 'cylinder number' of the next
+ * partition relative to the start of this one - I'm assuming it is.
+ *
+ * Also, which ID did Cumana use?
+ *
+ * This is totally unfinished, and will require more work to get it going.
+ * Hence it is totally untested.
+ */
+ do {
+ struct disc_record *dr;
+ unsigned int nr_sects;
+
+ if (!(minor & mask))
+ break;
+
+ if (!(bh = bread(dev, start_blk + 3, 1024)))
+ return -1;
+
+ dr = adfs_partition(hd, name, bh->b_data, first_sector, minor++);
+ if (!dr)
+ break;
+ name = NULL;
+
+ nr_sects = (bh->b_data[0x1fd] + (bh->b_data[0x1fe] << 8)) *
+ (dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) * dr->secspertrack;
+
+ if (!nr_sects)
+ break;
+
+ first = 0;
+ first_sector += nr_sects;
+ start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9);
+ nr_sects = 0; /* hmm - should be partition size */
+
+ switch (bh->b_data[0x1fc] & 15) {
+ case 0: /* No partition / ADFS? */
+ break;
+
+#ifdef CONFIG_ACORN_PARTITION_RISCIX
+ case PARTITION_RISCIX_SCSI: /* RiscIX - we don't know how to find the next one. */
+ minor = riscix_partition(hd, dev, first_sector, minor, nr_sects);
+ break;
+#endif
+
+ case PARTITION_LINUX:
+ minor = linux_partition(hd, dev, first_sector, minor, nr_sects);
+ break;
+ }
+ brelse(bh);
+ bh = NULL;
+ if (minor == -1)
+ return minor;
+ } while (1);
+ if (bh)
+ brelse(bh);
+ return first ? 0 : 1;
+}
+#endif
+
+#ifdef CONFIG_ACORN_PARTITION_ADFS
+/*
+ * Purpose: allocate ADFS partitions.
+ *
+ * Params : hd - pointer to gendisk structure to store partition info.
+ * dev - device number to access.
+ * first_sector- first readable sector on the device.
+ * minor - first available minor on device.
+ *
+ * Returns: -1 on error, 0 for no ADFS boot sector, 1 for ok.
+ *
+ * Alloc : hda = whole drive
+ * hda1 = ADFS partition on first drive.
+ * hda2 = non-ADFS partition.
+ */
+static int adfspart_check_ADFS(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
+ unsigned int minor)
+{
+ unsigned long start_sect, nr_sects, sectscyl, heads;
+ struct buffer_head *bh;
+ struct disc_record *dr;
+
+ if(get_ptable_blocksize(dev)!=1024)
+ return 0;
+
+ if (!(bh = bread(dev, 3, 1024)))
+ return -1;
+
+ dr = adfs_partition(hd, "ADFS", bh->b_data, first_sector, minor++);
+ if (!dr) {
+ brelse(bh);
+ return 0;
+ }
+
+ heads = dr->heads + ((dr->lowsector >> 6) & 1);
+ adfspart_setgeometry(dev, dr->secspertrack, heads, hd->part[MINOR(dev)].nr_sects);
+ sectscyl = dr->secspertrack * heads;
+
+ /*
+ * Work out start of non-adfs partition.
+ */
+ start_sect = ((bh->b_data[0x1fe] << 8) + bh->b_data[0x1fd]) * sectscyl;
+ nr_sects = hd->part[MINOR(dev)].nr_sects - start_sect;
+
+ if (start_sect) {
+ first_sector += start_sect;
+ /*
+ * we now have a problem - how to set the origional disk size if the
+ * disk doesn't report it, since there is no standard way of getting
+ * that info.
+ */
+ switch (bh->b_data[0x1fc] & 15) {
+#ifdef CONFIG_ACORN_PARTITION_RISCIX
+ case PARTITION_RISCIX_SCSI:
+ case PARTITION_RISCIX_MFM:
+ minor = riscix_partition(hd, dev, first_sector, minor, nr_sects);
+ break;
+#endif
+
+ case PARTITION_LINUX:
+ minor = linux_partition(hd, dev, first_sector, minor, nr_sects);
+ break;
+ }
+ }
+ brelse(bh);
+ return 1;
+}
+#endif
+
+#ifdef CONFIG_ACORN_PARTITION_ICS
+static int adfspart_check_ICSLinux(kdev_t dev, unsigned long block)
+{
+ struct buffer_head *bh;
+ unsigned int offset = block & 1 ? 512 : 0;
+ int result = 0;
+
+ if(get_ptable_blocksize(dev)!=1024)
+ return 0;
+
+ bh = bread(dev, block >> 1, 1024);
+
+ if (bh != NULL) {
+ if (memcmp(bh->b_data + offset, "LinuxPart", 9) == 0)
+ result = 1;
+
+ brelse(bh);
+ }
+
+ return result;
+}
+
+/*
+ * Purpose: allocate ICS partitions.
+ * Params : hd - pointer to gendisk structure to store partition info.
+ * dev - device number to access.
+ * first_sector- first readable sector on the device.
+ * minor - first available minor on device.
+ * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
+ * Alloc : hda = whole drive
+ * hda1 = ADFS partition 0 on first drive.
+ * hda2 = ADFS partition 1 on first drive.
+ * ..etc..
+ */
+static int adfspart_check_ICS(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
+ unsigned int minor)
+{
+ struct buffer_head *bh;
+ unsigned long sum;
+ unsigned int i, mask = (1 << hd->minor_shift) - 1;
+ struct ics_part { unsigned long start; signed long size; } *p;
+
+ if(get_ptable_blocksize(dev)!=1024)
+ return 0;
+
+ /*
+ * Try ICS style partitions - sector 0 contains partition info.
+ */
+ if (!(bh = bread(dev, 0, 1024)))
+ return -1;
+
+ /*
+ * check for a valid checksum
+ */
+ for (i = 0, sum = 0x50617274; i < 508; i++)
+ sum += bh->b_data[i];
+
+ if (sum != *(unsigned long *)(&bh->b_data[508])) {
+ brelse(bh);
+ return 0; /* not ICS partition table */
+ }
+
+ printk(" [ICS]");
+
+ for (p = (struct ics_part *)bh->b_data; p->size; p++) {
+ if ((minor & mask) == 0)
+ break;
+
+ if (p->size < 0 && adfspart_check_ICSLinux(dev, p->start)) {
+ /*
+ * We use the first sector to identify what type
+ * this partition is...
+ */
+ if (-p->size > 1)
+ add_gd_partition(hd, minor, first_sector + p->start + 1, -p->size - 1);
+ } else
+ add_gd_partition(hd, minor, first_sector + p->start, p->size);
+ minor++;
+ }
+
+ brelse(bh);
+ return 1;
+}
+#endif
+
+#ifdef CONFIG_ACORN_PARTITION_POWERTEC
+struct ptec_partition {
+ u32 unused1;
+ u32 unused2;
+ u32 start;
+ u32 size;
+ u32 unused5;
+ char type[8];
+};
+
+/*
+ * Purpose: allocate ICS partitions.
+ * Params : hd - pointer to gendisk structure to store partition info.
+ * dev - device number to access.
+ * first_sector- first readable sector on the device.
+ * minor - first available minor on device.
+ * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
+ * Alloc : hda = whole drive
+ * hda1 = ADFS partition 0 on first drive.
+ * hda2 = ADFS partition 1 on first drive.
+ * ..etc..
+ */
+static int adfspart_check_POWERTEC(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
+ unsigned int minor)
+{
+ struct buffer_head *bh;
+ struct ptec_partition *p;
+ unsigned char checksum;
+ int i;
+
+ if (!(bh = bread(dev, 0, 1024)))
+ return -1;
+
+ for (checksum = 0x2a, i = 0; i < 511; i++)
+ checksum += bh->b_data[i];
+
+ if (checksum != bh->b_data[511]) {
+ brelse(bh);
+ return 0;
+ }
+
+ printk(" [POWERTEC]");
+
+ for (i = 0, p = (struct ptec_partition *)bh->b_data; i < 12; i++, p++) {
+ if (p->size)
+ add_gd_partition(hd, minor, first_sector + p->start, p->size);
+ minor++;
+ }
+
+ brelse(bh);
+ return 1;
+}
+#endif
+
+/*
+ * Purpose: initialise all the partitions on an ADFS drive.
+ * These may be other ADFS partitions or a Linux/RiscBSD/RiscIX
+ * partition.
+ *
+ * Params : hd - pointer to gendisk structure to store devices partitions.
+ * dev - device number to access
+ * first_sector - first available sector on the disk.
+ * minor - first available minor on this device.
+ *
+ * Returns: -1 on error, 0 if not ADFS format, 1 if ok.
+ */
+int acorn_partition(struct gendisk *hd, kdev_t dev,
+ unsigned long first_sector, int first_part_minor)
+{
+ int r = 0;
+
+#ifdef CONFIG_ACORN_PARTITION_ICS
+ if (r == 0)
+ r = adfspart_check_ICS(hd, dev, first_sector, first_part_minor);
+#endif
+#ifdef CONFIG_ACORN_PARTITION_CUMANA
+ if (r == 0)
+ r = adfspart_check_CUMANA(hd, dev, first_sector, first_part_minor);
+#endif
+#ifdef CONFIG_ACORN_PARTITION_ADFS
+ if (r == 0)
+ r = adfspart_check_ADFS(hd, dev, first_sector, first_part_minor);
+#endif
+#ifdef CONFIG_ACORN_PARTITION_POWERTEC
+ if (r == 0)
+ r = adfspart_check_POWERTEC(hd, dev, first_sector, first_part_minor);
+#endif
+ if (r < 0)
+ printk(" unable to read boot sectors / partition sectors\n");
+ else if (r)
+ printk("\n");
+ return r;
+}
diff --git a/fs/partitions/acorn.h b/fs/partitions/acorn.h
new file mode 100644
index 000000000..932c305e6
--- /dev/null
+++ b/fs/partitions/acorn.h
@@ -0,0 +1,68 @@
+/*
+ * fs/partitions/acorn.h
+ *
+ * Copyright (C) 1996-1998 Russell King
+ */
+#include <linux/adfs_fs.h>
+
+/*
+ * Offset in bytes of the boot block on the disk.
+ */
+#define BOOT_SECTOR_ADDRESS 0xc00
+
+/*
+ * Disc record size
+ */
+#define RECSIZE 60
+
+/*
+ * Disc record
+ */
+struct disc_record {
+ unsigned char log2secsize;
+ unsigned char secspertrack;
+ unsigned char heads;
+ unsigned char density;
+ unsigned char idlen;
+ unsigned char log2bpmb;
+ unsigned char skew;
+ unsigned char bootoption;
+ unsigned char lowsector;
+ unsigned char nzones;
+ unsigned short zone_spare;
+ unsigned long root;
+ unsigned long disc_size;
+ unsigned short disc_id;
+ unsigned char disc_name[10];
+ unsigned long disc_type;
+ unsigned long disc_size_high;
+ unsigned char log2sharesize:4;
+ unsigned char unused:4;
+ unsigned char big_flag:1;
+};
+
+/*
+ * Partition types. (Oh for reusability)
+ */
+#define PARTITION_RISCIX_MFM 1
+#define PARTITION_RISCIX_SCSI 2
+#define PARTITION_LINUX 9
+
+struct riscix_part {
+ unsigned long start;
+ unsigned long length;
+ unsigned long one;
+ char name[16];
+};
+
+struct riscix_record {
+ unsigned long magic;
+#define RISCIX_MAGIC (0x4a657320)
+ unsigned long date;
+ struct riscix_part part[8];
+};
+
+int
+acorn_partition(struct gendisk *hd, kdev_t dev,
+ unsigned long first_sector, int first_part_minor);
+
diff --git a/fs/partitions/amiga.c b/fs/partitions/amiga.c
new file mode 100644
index 000000000..aa8605315
--- /dev/null
+++ b/fs/partitions/amiga.c
@@ -0,0 +1,120 @@
+/*
+ * fs/partitions/amiga.c
+ *
+ * Code extracted from drivers/block/genhd.c
+ *
+ * Copyright (C) 1991-1998 Linus Torvalds
+ * Re-organised Feb 1998 Russell King
+ */
+
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+
+#include <asm/byteorder.h>
+#include <linux/affs_hardblocks.h>
+
+#include "check.h"
+#include "amiga.h"
+
+static __inline__ u32
+checksum_block(u32 *m, int size)
+{
+ u32 sum = 0;
+
+ while (size--)
+ sum += be32_to_cpu(*m++);
+ return sum;
+}
+
+int
+amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int first_part_minor)
+{
+ struct buffer_head *bh;
+ struct RigidDiskBlock *rdb;
+ struct PartitionBlock *pb;
+ int start_sect;
+ int nr_sects;
+ int blk;
+ int part, res;
+ int old_blocksize;
+ int blocksize;
+
+ old_blocksize = get_ptable_blocksize(dev);
+ blocksize = get_hardsect_size(dev);
+
+ if (blocksize < 512)
+ blocksize = 512;
+
+ set_blocksize(dev,blocksize);
+ res = 0;
+
+ for (blk = 0; blk < RDB_ALLOCATION_LIMIT; blk++) {
+ if(!(bh = bread(dev,blk,blocksize))) {
+ printk("Dev %s: unable to read RDB block %d\n",
+ kdevname(dev),blk);
+ goto rdb_done;
+ }
+ if (*(u32 *)bh->b_data == cpu_to_be32(IDNAME_RIGIDDISK)) {
+ rdb = (struct RigidDiskBlock *)bh->b_data;
+ if (checksum_block((u32 *)bh->b_data,be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)) {
+ /* Try again with 0xdc..0xdf zeroed, Windows might have
+ * trashed it.
+ */
+ *(u32 *)(&bh->b_data[0xdc]) = 0;
+ if (checksum_block((u32 *)bh->b_data,
+ be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)) {
+ brelse(bh);
+ printk("Dev %s: RDB in block %d has bad checksum\n",
+ kdevname(dev),blk);
+ continue;
+ }
+ printk("Warning: Trashed word at 0xd0 in block %d "
+ "ignored in checksum calculation\n",blk);
+ }
+ printk(" RDSK");
+ blk = be32_to_cpu(rdb->rdb_PartitionList);
+ brelse(bh);
+ for (part = 1; blk > 0 && part <= 16; part++) {
+ if (!(bh = bread(dev,blk,blocksize))) {
+ printk("Dev %s: unable to read partition block %d\n",
+ kdevname(dev),blk);
+ goto rdb_done;
+ }
+ pb = (struct PartitionBlock *)bh->b_data;
+ blk = be32_to_cpu(pb->pb_Next);
+ if (pb->pb_ID == cpu_to_be32(IDNAME_PARTITION) && checksum_block(
+ (u32 *)pb,be32_to_cpu(pb->pb_SummedLongs) & 0x7F) == 0 ) {
+
+ /* Tell Kernel about it */
+
+ if (!(nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 -
+ be32_to_cpu(pb->pb_Environment[9])) *
+ be32_to_cpu(pb->pb_Environment[3]) *
+ be32_to_cpu(pb->pb_Environment[5]))) {
+ brelse(bh);
+ continue;
+ }
+ start_sect = be32_to_cpu(pb->pb_Environment[9]) *
+ be32_to_cpu(pb->pb_Environment[3]) *
+ be32_to_cpu(pb->pb_Environment[5]);
+ add_gd_partition(hd,first_part_minor,start_sect,nr_sects);
+ first_part_minor++;
+ res = 1;
+ }
+ brelse(bh);
+ }
+ printk("\n");
+ break;
+ }
+ else
+ brelse(bh);
+ }
+
+rdb_done:
+ set_blocksize(dev,old_blocksize);
+ return res;
+}
diff --git a/fs/partitions/amiga.h b/fs/partitions/amiga.h
new file mode 100644
index 000000000..37c6ec144
--- /dev/null
+++ b/fs/partitions/amiga.h
@@ -0,0 +1,8 @@
+/*
+ * fs/partitions/amiga.h
+ */
+
+int
+amiga_partition(struct gendisk *hd, kdev_t dev,
+ unsigned long first_sector, int first_part_minor);
+
diff --git a/fs/partitions/atari.c b/fs/partitions/atari.c
new file mode 100644
index 000000000..ae8596e6a
--- /dev/null
+++ b/fs/partitions/atari.c
@@ -0,0 +1,177 @@
+/*
+ * fs/partitions/atari.c
+ *
+ * Code extracted from drivers/block/genhd.c
+ *
+ * Copyright (C) 1991-1998 Linus Torvalds
+ * Re-organised Feb 1998 Russell King
+ */
+
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/ctype.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+
+#include "check.h"
+#include "atari.h"
+
+/* ++guenther: this should be settable by the user ("make config")?.
+ */
+#define ICD_PARTS
+
+/* check if a partition entry looks valid -- Atari format is assumed if at
+ least one of the primary entries is ok this way */
+#define VALID_PARTITION(pi,hdsiz) \
+ (((pi)->flg & 1) && \
+ isalnum((pi)->id[0]) && isalnum((pi)->id[1]) && isalnum((pi)->id[2]) && \
+ be32_to_cpu((pi)->st) <= (hdsiz) && \
+ be32_to_cpu((pi)->st) + be32_to_cpu((pi)->siz) <= (hdsiz))
+
+int atari_partition (struct gendisk *hd, kdev_t dev,
+ unsigned long first_sector, int first_part_minor)
+{
+ int minor = first_part_minor, m_lim = first_part_minor + hd->max_p;
+ struct buffer_head *bh;
+ struct rootsector *rs;
+ struct partition_info *pi;
+ u32 extensect;
+ u32 hd_size;
+#ifdef ICD_PARTS
+ int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
+#endif
+
+ bh = bread (dev, 0, get_ptable_blocksize(dev));
+ if (!bh) {
+ printk (" unable to read block 0 (partition table)\n");
+ return -1;
+ }
+
+ /* Verify this is an Atari rootsector: */
+ rs = (struct rootsector *) bh->b_data;
+ hd_size = hd->part[minor - 1].nr_sects;
+ if (!VALID_PARTITION(&rs->part[0], hd_size) &&
+ !VALID_PARTITION(&rs->part[1], hd_size) &&
+ !VALID_PARTITION(&rs->part[2], hd_size) &&
+ !VALID_PARTITION(&rs->part[3], hd_size)) {
+ /* if there's no valid primary partition, assume that no Atari
+ format partition table (there's no reliable magic or the like
+ :-() */
+ return 0;
+ }
+
+ pi = &rs->part[0];
+ printk (" AHDI");
+ for (; pi < &rs->part[4] && minor < m_lim; minor++, pi++)
+ {
+ if (pi->flg & 1)
+ /* active partition */
+ {
+ if (memcmp (pi->id, "XGM", 3) == 0)
+ /* extension partition */
+ {
+ struct rootsector *xrs;
+ struct buffer_head *xbh;
+ ulong partsect;
+
+#ifdef ICD_PARTS
+ part_fmt = 1;
+#endif
+ printk(" XGM<");
+ partsect = extensect = be32_to_cpu(pi->st);
+ while (1)
+ {
+ xbh = bread (dev, partsect / 2, get_ptable_blocksize(dev));
+ if (!xbh)
+ {
+ printk (" block %ld read failed\n", partsect);
+ brelse(bh);
+ return 0;
+ }
+ if (partsect & 1)
+ xrs = (struct rootsector *) &xbh->b_data[512];
+ else
+ xrs = (struct rootsector *) &xbh->b_data[0];
+
+ /* ++roman: sanity check: bit 0 of flg field must be set */
+ if (!(xrs->part[0].flg & 1)) {
+ printk( "\nFirst sub-partition in extended partition is not valid!\n" );
+ break;
+ }
+
+ add_gd_partition(hd, minor,
+ partsect + be32_to_cpu(xrs->part[0].st),
+ be32_to_cpu(xrs->part[0].siz));
+
+ if (!(xrs->part[1].flg & 1)) {
+ /* end of linked partition list */
+ brelse( xbh );
+ break;
+ }
+ if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
+ printk( "\nID of extended partition is not XGM!\n" );
+ brelse( xbh );
+ break;
+ }
+
+ partsect = be32_to_cpu(xrs->part[1].st) + extensect;
+ brelse (xbh);
+ minor++;
+ if (minor >= m_lim) {
+ printk( "\nMaximum number of partitions reached!\n" );
+ break;
+ }
+ }
+ printk(" >");
+ }
+ else
+ {
+ /* we don't care about other id's */
+ add_gd_partition (hd, minor, be32_to_cpu(pi->st),
+ be32_to_cpu(pi->siz));
+ }
+ }
+ }
+#ifdef ICD_PARTS
+ if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */
+ {
+ pi = &rs->icdpart[0];
+ /* sanity check: no ICD format if first partition invalid */
+ if (memcmp (pi->id, "GEM", 3) == 0 ||
+ memcmp (pi->id, "BGM", 3) == 0 ||
+ memcmp (pi->id, "LNX", 3) == 0 ||
+ memcmp (pi->id, "SWP", 3) == 0 ||
+ memcmp (pi->id, "RAW", 3) == 0 )
+ {
+ printk(" ICD<");
+ for (; pi < &rs->icdpart[8] && minor < m_lim; minor++, pi++)
+ {
+ /* accept only GEM,BGM,RAW,LNX,SWP partitions */
+ if (pi->flg & 1 &&
+ (memcmp (pi->id, "GEM", 3) == 0 ||
+ memcmp (pi->id, "BGM", 3) == 0 ||
+ memcmp (pi->id, "LNX", 3) == 0 ||
+ memcmp (pi->id, "SWP", 3) == 0 ||
+ memcmp (pi->id, "RAW", 3) == 0) )
+ {
+ part_fmt = 2;
+ add_gd_partition (hd, minor, be32_to_cpu(pi->st),
+ be32_to_cpu(pi->siz));
+ }
+ }
+ printk(" >");
+ }
+ }
+#endif
+ brelse (bh);
+
+ printk ("\n");
+
+ return 1;
+}
+
diff --git a/fs/partitions/atari.h b/fs/partitions/atari.h
new file mode 100644
index 000000000..6d19c93e5
--- /dev/null
+++ b/fs/partitions/atari.h
@@ -0,0 +1,36 @@
+/*
+ * fs/partitions/atari.h
+ * Moved by Russell King from:
+ *
+ * linux/include/linux/atari_rootsec.h
+ * definitions for Atari Rootsector layout
+ * by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
+ *
+ * modified for ICD/Supra partitioning scheme restricted to at most 12
+ * partitions
+ * by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de)
+ */
+
+struct partition_info
+{
+ u8 flg; /* bit 0: active; bit 7: bootable */
+ char id[3]; /* "GEM", "BGM", "XGM", or other */
+ u32 st; /* start of partition */
+ u32 siz; /* length of partition */
+};
+
+struct rootsector
+{
+ char unused[0x156]; /* room for boot code */
+ struct partition_info icdpart[8]; /* info for ICD-partitions 5..12 */
+ char unused2[0xc];
+ u32 hd_siz; /* size of disk in blocks */
+ struct partition_info part[4];
+ u32 bsl_st; /* start of bad sector list */
+ u32 bsl_cnt; /* length of bad sector list */
+ u16 checksum; /* checksum for bootable disks */
+} __attribute__((__packed__));
+
+int atari_partition (struct gendisk *hd, kdev_t dev,
+ unsigned long first_sector, int first_part_minor);
+
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
new file mode 100644
index 000000000..76476f512
--- /dev/null
+++ b/fs/partitions/check.c
@@ -0,0 +1,334 @@
+/*
+ * Code extracted from drivers/block/genhd.c
+ * Copyright (C) 1991-1998 Linus Torvalds
+ * Re-organised Feb 1998 Russell King
+ *
+ * We now have independent partition support from the
+ * block drivers, which allows all the partition code to
+ * be grouped in one location, and it to be mostly self
+ * contained.
+ *
+ * Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/init.h>
+
+#include "check.h"
+
+#include "acorn.h"
+#include "amiga.h"
+#include "atari.h"
+#include "mac.h"
+#include "msdos.h"
+#include "osf.h"
+#include "sgi.h"
+#include "sun.h"
+
+extern void device_init(void);
+extern void md_setup_drive(void);
+extern int *blk_size[];
+extern void rd_load(void);
+extern void initrd_load(void);
+
+struct gendisk *gendisk_head;
+
+static int (*check_part[])(struct gendisk *hd, kdev_t dev, unsigned long first_sect, int first_minor) = {
+#ifdef CONFIG_ACORN_PARTITION
+ acorn_partition,
+#endif
+#ifdef CONFIG_MSDOS_PARTITION
+ msdos_partition,
+#endif
+#ifdef CONFIG_OSF_PARTITION
+ osf_partition,
+#endif
+#ifdef CONFIG_SUN_PARTITION
+ sun_partition,
+#endif
+#ifdef CONFIG_AMIGA_PARTITION
+ amiga_partition,
+#endif
+#ifdef CONFIG_ATARI_PARTITION
+ atari_partition,
+#endif
+#ifdef CONFIG_MAC_PARTITION
+ mac_partition,
+#endif
+#ifdef CONFIG_SGI_PARTITION
+ sgi_partition,
+#endif
+#ifdef CONFIG_ULTRIX_PARTITION
+ ultrix_partition,
+#endif
+ NULL
+};
+
+/*
+ * disk_name() is used by genhd.c and blkpg.c.
+ * It formats the devicename of the indicated disk into
+ * the supplied buffer (of size at least 32), and returns
+ * a pointer to that same buffer (for convenience).
+ */
+char *disk_name (struct gendisk *hd, int minor, char *buf)
+{
+ unsigned int part;
+ const char *maj = hd->major_name;
+ int unit = (minor >> hd->minor_shift) + 'a';
+
+ /*
+ * IDE devices use multiple major numbers, but the drives
+ * are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
+ * This requires special handling here.
+ */
+ switch (hd->major) {
+ case IDE9_MAJOR:
+ unit += 2;
+ case IDE8_MAJOR:
+ unit += 2;
+ case IDE7_MAJOR:
+ unit += 2;
+ case IDE6_MAJOR:
+ unit += 2;
+ case IDE5_MAJOR:
+ unit += 2;
+ case IDE4_MAJOR:
+ unit += 2;
+ case IDE3_MAJOR:
+ unit += 2;
+ case IDE2_MAJOR:
+ unit += 2;
+ case IDE1_MAJOR:
+ unit += 2;
+ case IDE0_MAJOR:
+ maj = "hd";
+ break;
+ }
+ part = minor & ((1 << hd->minor_shift) - 1);
+ if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) {
+ unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16;
+ if (unit > 'z') {
+ unit -= 'z' + 1;
+ sprintf(buf, "sd%c%c", 'a' + unit / 26, 'a' + unit % 26);
+ if (part)
+ sprintf(buf + 4, "%d", part);
+ return buf;
+ }
+ }
+ if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) {
+ int ctlr = hd->major - COMPAQ_SMART2_MAJOR;
+ int disk = minor >> hd->minor_shift;
+ int part = minor & (( 1 << hd->minor_shift) - 1);
+ if (part == 0)
+ sprintf(buf, "%s/c%dd%d", maj, ctlr, disk);
+ else
+ sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part);
+ return buf;
+ }
+ if (hd->major >= DAC960_MAJOR && hd->major <= DAC960_MAJOR+7) {
+ int ctlr = hd->major - DAC960_MAJOR;
+ int disk = minor >> hd->minor_shift;
+ int part = minor & (( 1 << hd->minor_shift) - 1);
+ if (part == 0)
+ sprintf(buf, "%s/c%dd%d", maj, ctlr, disk);
+ else
+ sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part);
+ return buf;
+ }
+ if (part)
+ sprintf(buf, "%s%c%d", maj, unit, part);
+ else
+ sprintf(buf, "%s%c", maj, unit);
+ return buf;
+}
+
+/*
+ * Add a partitions details to the devices partition description.
+ */
+void add_gd_partition(struct gendisk *hd, int minor, int start, int size)
+{
+ char buf[40];
+ hd->part[minor].start_sect = start;
+ hd->part[minor].nr_sects = size;
+ if (hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7)
+ printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
+ else
+ printk(" %s", disk_name(hd, minor, buf));
+}
+
+int get_hardsect_size(kdev_t dev)
+{
+ if (hardsect_size[MAJOR(dev)] != NULL)
+ return hardsect_size[MAJOR(dev)][MINOR(dev)];
+ else
+ return 512;
+}
+
+unsigned int get_ptable_blocksize(kdev_t dev)
+{
+ int ret = 1024;
+
+ /*
+ * See whether the low-level driver has given us a minumum blocksize.
+ * If so, check to see whether it is larger than the default of 1024.
+ */
+ if (!blksize_size[MAJOR(dev)])
+ return ret;
+
+ /*
+ * Check for certain special power of two sizes that we allow.
+ * With anything larger than 1024, we must force the blocksize up to
+ * the natural blocksize for the device so that we don't have to try
+ * and read partial sectors. Anything smaller should be just fine.
+ */
+
+ switch (blksize_size[MAJOR(dev)][MINOR(dev)]) {
+ case 2048:
+ ret = 2048;
+ break;
+ case 4096:
+ ret = 4096;
+ break;
+ case 8192:
+ ret = 8192;
+ break;
+ case 1024:
+ case 512:
+ case 256:
+ case 0:
+ /*
+ * These are all OK.
+ */
+ break;
+ default:
+ panic("Strange blocksize for partition table\n");
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_PROC_FS
+int get_partition_list(char * page)
+{
+ struct gendisk *p;
+ char buf[40];
+ int n, len;
+
+ len = sprintf(page, "major minor #blocks name\n\n");
+ for (p = gendisk_head; p; p = p->next) {
+ for (n=0; n < (p->nr_real << p->minor_shift); n++) {
+ if (p->part[n].nr_sects && len < PAGE_SIZE - 80) {
+ len += sprintf(page+len,
+ "%4d %4d %10d %s\n",
+ p->major, n, p->sizes[n],
+ disk_name(p, n, buf));
+ }
+ }
+ }
+ return len;
+}
+#endif
+
+void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor)
+{
+ static int first_time = 1;
+ unsigned long first_sector;
+ char buf[40];
+ int i;
+
+ if (first_time)
+ printk(KERN_INFO "Partition check:\n");
+ first_time = 0;
+ first_sector = hd->part[MINOR(dev)].start_sect;
+
+ /*
+ * This is a kludge to allow the partition check to be
+ * skipped for specific drives (e.g. IDE CD-ROM drives)
+ */
+ if ((int)first_sector == -1) {
+ hd->part[MINOR(dev)].start_sect = 0;
+ return;
+ }
+
+ printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf));
+ for (i = 0; check_part[i]; i++)
+ if (check_part[i](hd, dev, first_sector, first_part_minor))
+ return;
+
+ printk(" unknown partition table\n");
+}
+
+/*
+ * This function will re-read the partition tables for a given device,
+ * and set things back up again. There are some important caveats,
+ * however. You must ensure that no one is using the device, and no one
+ * can start using the device while this function is being executed.
+ *
+ * Much of the cleanup from the old partition tables should have already been
+ * done
+ */
+void resetup_one_dev(struct gendisk *dev, int drive)
+{
+ int i;
+ int first_minor = drive << dev->minor_shift;
+ int end_minor = first_minor + dev->max_p;
+
+ blk_size[dev->major] = NULL;
+ check_partition(dev, MKDEV(dev->major, first_minor), 1 + first_minor);
+
+ /*
+ * We need to set the sizes array before we will be able to access
+ * any of the partitions on this device.
+ */
+ if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */
+ for (i = first_minor; i < end_minor; i++)
+ dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
+ blk_size[dev->major] = dev->sizes;
+ }
+}
+
+static inline void setup_dev(struct gendisk *dev)
+{
+ int i, drive;
+ int end_minor = dev->max_nr * dev->max_p;
+
+ blk_size[dev->major] = NULL;
+ for (i = 0; i < end_minor; i++) {
+ dev->part[i].start_sect = 0;
+ dev->part[i].nr_sects = 0;
+ dev->sizes[i] = 0;
+ }
+ dev->init(dev);
+ for (drive = 0 ; drive < dev->nr_real ; drive++)
+ resetup_one_dev(dev, drive);
+}
+
+int __init partition_setup(void)
+{
+ struct gendisk *p;
+
+ device_init();
+
+ for (p = gendisk_head ; p ; p=p->next)
+ setup_dev(p);
+
+#ifdef CONFIG_BLK_DEV_RAM
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start && mount_initrd) initrd_load();
+ else
+#endif
+ rd_load();
+#endif
+#ifdef CONFIG_MD_BOOT
+ md_setup_drive();
+#endif
+
+ return 0;
+}
+
+__initcall(partition_setup);
diff --git a/fs/partitions/check.h b/fs/partitions/check.h
new file mode 100644
index 000000000..804d54517
--- /dev/null
+++ b/fs/partitions/check.h
@@ -0,0 +1,10 @@
+/*
+ * add_partition adds a partitions details to the devices partition
+ * description.
+ */
+void add_gd_partition(struct gendisk *hd, int minor, int start, int size);
+
+/*
+ * Get the default block size for this device
+ */
+unsigned int get_ptable_blocksize(kdev_t dev);
diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c
new file mode 100644
index 000000000..41364385d
--- /dev/null
+++ b/fs/partitions/mac.c
@@ -0,0 +1,110 @@
+/*
+ * fs/partitions/mac.c
+ *
+ * Code extracted from drivers/block/genhd.c
+ * Copyright (C) 1991-1998 Linus Torvalds
+ * Re-organised Feb 1998 Russell King
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/ctype.h>
+
+#include <asm/system.h>
+
+#include "check.h"
+#include "mac.h"
+
+#ifdef CONFIG_PPC
+extern void note_bootable_part(kdev_t dev, int part);
+#endif
+
+/*
+ * Code to understand MacOS partition tables.
+ */
+
+int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_part_minor)
+{
+ struct buffer_head *bh;
+ int blk, blocks_in_map;
+ int dev_bsize, dev_pos, pos;
+ unsigned secsize;
+#ifdef CONFIG_PPC
+ int first_bootable = 1;
+#endif
+ struct mac_partition *part;
+ struct mac_driver_desc *md;
+
+ dev_bsize = get_ptable_blocksize(dev);
+ dev_pos = 0;
+ /* Get 0th block and look at the first partition map entry. */
+ if ((bh = bread(dev, 0, dev_bsize)) == 0) {
+ printk("%s: error reading partition table\n",
+ kdevname(dev));
+ return -1;
+ }
+ md = (struct mac_driver_desc *) bh->b_data;
+ if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) {
+ brelse(bh);
+ return 0;
+ }
+ secsize = be16_to_cpu(md->block_size);
+ if (secsize >= dev_bsize) {
+ brelse(bh);
+ dev_pos = secsize;
+ if ((bh = bread(dev, secsize/dev_bsize, dev_bsize)) == 0) {
+ printk("%s: error reading partition table\n",
+ kdevname(dev));
+ return -1;
+ }
+ }
+ part = (struct mac_partition *) (bh->b_data + secsize - dev_pos);
+ if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) {
+ brelse(bh);
+ return 0; /* not a MacOS disk */
+ }
+ blocks_in_map = be32_to_cpu(part->map_count);
+ for (blk = 1; blk <= blocks_in_map; ++blk) {
+ pos = blk * secsize;
+ if (pos >= dev_pos + dev_bsize) {
+ brelse(bh);
+ dev_pos = pos;
+ if ((bh = bread(dev, pos/dev_bsize, dev_bsize)) == 0) {
+ printk("%s: error reading partition table\n",
+ kdevname(dev));
+ return -1;
+ }
+ }
+ part = (struct mac_partition *) (bh->b_data + pos - dev_pos);
+ if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
+ break;
+ blocks_in_map = be32_to_cpu(part->map_count);
+ add_gd_partition(hd, first_part_minor,
+ fsec + be32_to_cpu(part->start_block) * (secsize/512),
+ be32_to_cpu(part->block_count) * (secsize/512));
+
+#ifdef CONFIG_PPC
+ /*
+ * If this is the first bootable partition, tell the
+ * setup code, in case it wants to make this the root.
+ */
+ if ( (_machine == _MACH_Pmac) && first_bootable
+ && (be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
+ && strcasecmp(part->processor, "powerpc") == 0) {
+ note_bootable_part(dev, blk);
+ first_bootable = 0;
+ }
+#endif /* CONFIG_PPC */
+
+ ++first_part_minor;
+ }
+ brelse(bh);
+ printk("\n");
+ return 1;
+}
+
diff --git a/fs/partitions/mac.h b/fs/partitions/mac.h
new file mode 100644
index 000000000..1a3fd68de
--- /dev/null
+++ b/fs/partitions/mac.h
@@ -0,0 +1,44 @@
+/*
+ * fs/partitions/mac.h
+ */
+
+#define MAC_PARTITION_MAGIC 0x504d
+
+/* type field value for A/UX or other Unix partitions */
+#define APPLE_AUX_TYPE "Apple_UNIX_SVR2"
+
+struct mac_partition {
+ __u16 signature; /* expected to be MAC_PARTITION_MAGIC */
+ __u16 res1;
+ __u32 map_count; /* # blocks in partition map */
+ __u32 start_block; /* absolute starting block # of partition */
+ __u32 block_count; /* number of blocks in partition */
+ char name[32]; /* partition name */
+ char type[32]; /* string type description */
+ __u32 data_start; /* rel block # of first data block */
+ __u32 data_count; /* number of data blocks */
+ __u32 status; /* partition status bits */
+ __u32 boot_start;
+ __u32 boot_size;
+ __u32 boot_load;
+ __u32 boot_load2;
+ __u32 boot_entry;
+ __u32 boot_entry2;
+ __u32 boot_cksum;
+ char processor[16]; /* identifies ISA of boot */
+ /* there is more stuff after this that we don't need */
+};
+
+#define MAC_STATUS_BOOTABLE 8 /* partition is bootable */
+
+#define MAC_DRIVER_MAGIC 0x4552
+
+/* Driver descriptor structure, in block 0 */
+struct mac_driver_desc {
+ __u16 signature; /* expected to be MAC_DRIVER_MAGIC */
+ __u16 block_size;
+ __u32 block_count;
+ /* ... more stuff */
+};
+
+int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_part_minor);
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c
new file mode 100644
index 000000000..a4ba9253b
--- /dev/null
+++ b/fs/partitions/msdos.c
@@ -0,0 +1,490 @@
+/*
+ * fs/partitions/msdos.c
+ *
+ * Code extracted from drivers/block/genhd.c
+ * Copyright (C) 1991-1998 Linus Torvalds
+ *
+ * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
+ * in the early extended-partition checks and added DM partitions
+ *
+ * Support for DiskManager v6.0x added by Mark Lord,
+ * with information provided by OnTrack. This now works for linux fdisk
+ * and LILO, as well as loadlin and bootln. Note that disks other than
+ * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
+ *
+ * More flexible handling of extended partitions - aeb, 950831
+ *
+ * Check partition table on IDE disks for common CHS translations
+ *
+ * Re-organised Feb 1998 Russell King
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+
+#include <asm/system.h>
+
+#include "check.h"
+#include "msdos.h"
+
+static int current_minor;
+
+/*
+ * Many architectures don't like unaligned accesses, which is
+ * frequently the case with the nr_sects and start_sect partition
+ * table entries.
+ */
+#include <asm/unaligned.h>
+
+#define SYS_IND(p) (get_unaligned(&p->sys_ind))
+#define NR_SECTS(p) ({ __typeof__(p->nr_sects) __a = \
+ get_unaligned(&p->nr_sects); \
+ le32_to_cpu(__a); \
+ })
+
+#define START_SECT(p) ({ __typeof__(p->start_sect) __a = \
+ get_unaligned(&p->start_sect); \
+ le32_to_cpu(__a); \
+ })
+
+static inline int is_extended_partition(struct partition *p)
+{
+ return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
+ SYS_IND(p) == WIN98_EXTENDED_PARTITION ||
+ SYS_IND(p) == LINUX_EXTENDED_PARTITION);
+}
+
+/*
+ * Create devices for each logical partition in an extended partition.
+ * The logical partitions form a linked list, with each entry being
+ * a partition table with two entries. The first entry
+ * is the real data partition (with a start relative to the partition
+ * table start). The second is a pointer to the next logical partition
+ * (with a start relative to the entire extended partition).
+ * We do not create a Linux partition for the partition tables, but
+ * only for the actual data partitions.
+ */
+
+static void extended_partition(struct gendisk *hd, kdev_t dev)
+{
+ struct buffer_head *bh;
+ struct partition *p;
+ unsigned long first_sector, first_size, this_sector, this_size;
+ int mask = (1 << hd->minor_shift) - 1;
+ int sector_size = get_hardsect_size(dev) / 512;
+ int loopct = 0; /* number of links followed
+ without finding a data partition */
+ int i;
+
+ first_sector = hd->part[MINOR(dev)].start_sect;
+ first_size = hd->part[MINOR(dev)].nr_sects;
+ this_sector = first_sector;
+
+ while (1) {
+ if (++loopct > 100)
+ return;
+ if ((current_minor & mask) == 0)
+ return;
+ if (!(bh = bread(dev,0,get_ptable_blocksize(dev))))
+ return;
+
+ if ((*(__u16 *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC))
+ goto done;
+
+ p = (struct partition *) (0x1BE + bh->b_data);
+
+ this_size = hd->part[MINOR(dev)].nr_sects;
+
+ /*
+ * Usually, the first entry is the real data partition,
+ * the 2nd entry is the next extended partition, or empty,
+ * and the 3rd and 4th entries are unused.
+ * However, DRDOS sometimes has the extended partition as
+ * the first entry (when the data partition is empty),
+ * and OS/2 seems to use all four entries.
+ */
+
+ /*
+ * First process the data partition(s)
+ */
+ for (i=0; i<4; i++, p++) {
+ if (!NR_SECTS(p) || is_extended_partition(p))
+ continue;
+
+ /* Check the 3rd and 4th entries -
+ these sometimes contain random garbage */
+ if (i >= 2
+ && START_SECT(p) + NR_SECTS(p) > this_size
+ && (this_sector + START_SECT(p) < first_sector ||
+ this_sector + START_SECT(p) + NR_SECTS(p) >
+ first_sector + first_size))
+ continue;
+
+ add_gd_partition(hd, current_minor,
+ this_sector+START_SECT(p)*sector_size,
+ NR_SECTS(p)*sector_size);
+ current_minor++;
+ loopct = 0;
+ if ((current_minor & mask) == 0)
+ goto done;
+ }
+ /*
+ * Next, process the (first) extended partition, if present.
+ * (So far, there seems to be no reason to make
+ * extended_partition() recursive and allow a tree
+ * of extended partitions.)
+ * It should be a link to the next logical partition.
+ * Create a minor for this just long enough to get the next
+ * partition table. The minor will be reused for the next
+ * data partition.
+ */
+ p -= 4;
+ for (i=0; i<4; i++, p++)
+ if(NR_SECTS(p) && is_extended_partition(p))
+ break;
+ if (i == 4)
+ goto done; /* nothing left to do */
+
+ hd->part[current_minor].nr_sects = NR_SECTS(p) * sector_size; /* JSt */
+ hd->part[current_minor].start_sect = first_sector + START_SECT(p) * sector_size;
+ this_sector = first_sector + START_SECT(p) * sector_size;
+ dev = MKDEV(hd->major, current_minor);
+
+ /* Use bforget(), as we have changed the disk geometry */
+ bforget(bh);
+ }
+done:
+ bforget(bh);
+}
+
+#ifdef CONFIG_SOLARIS_X86_PARTITION
+static void
+solaris_x86_partition(struct gendisk *hd, kdev_t dev, long offset) {
+
+ struct buffer_head *bh;
+ struct solaris_x86_vtoc *v;
+ struct solaris_x86_slice *s;
+ int i;
+
+ if(!(bh = bread(dev, 0, get_ptable_blocksize(dev))))
+ return;
+ v = (struct solaris_x86_vtoc *)(bh->b_data + 512);
+ if(v->v_sanity != SOLARIS_X86_VTOC_SANE) {
+ brelse(bh);
+ return;
+ }
+ printk(" <solaris:");
+ if(v->v_version != 1) {
+ printk(" cannot handle version %ld vtoc>", v->v_version);
+ brelse(bh);
+ return;
+ }
+ for(i=0; i<SOLARIS_X86_NUMSLICE; i++) {
+ s = &v->v_slice[i];
+
+ if (s->s_size == 0)
+ continue;
+ printk(" [s%d]", i);
+ /* solaris partitions are relative to current MS-DOS
+ * one but add_gd_partition starts relative to sector
+ * zero of the disk. Therefore, must add the offset
+ * of the current partition */
+ add_gd_partition(hd, current_minor, s->s_start+offset, s->s_size);
+ current_minor++;
+ }
+ brelse(bh);
+ printk(" >");
+}
+#endif
+
+#ifdef CONFIG_BSD_DISKLABEL
+static void check_and_add_bsd_partition(struct gendisk *hd,
+ struct bsd_partition *bsd_p, kdev_t dev)
+{
+ struct hd_struct *lin_p;
+ /* check relative position of partitions. */
+ for (lin_p = hd->part + 1 + MINOR(dev);
+ lin_p - hd->part - MINOR(dev) < current_minor; lin_p++) {
+ /* no relationship -> try again */
+ if (lin_p->start_sect + lin_p->nr_sects <= bsd_p->p_offset
+ || lin_p->start_sect >= bsd_p->p_offset + bsd_p->p_size)
+ continue;
+ /* equal -> no need to add */
+ if (lin_p->start_sect == bsd_p->p_offset &&
+ lin_p->nr_sects == bsd_p->p_size)
+ return;
+ /* bsd living within dos partition */
+ if (lin_p->start_sect <= bsd_p->p_offset && lin_p->start_sect
+ + lin_p->nr_sects >= bsd_p->p_offset + bsd_p->p_size) {
+#ifdef DEBUG_BSD_DISKLABEL
+ printk("w: %d %ld+%ld,%d+%d",
+ lin_p - hd->part,
+ lin_p->start_sect, lin_p->nr_sects,
+ bsd_p->p_offset, bsd_p->p_size);
+#endif
+ break;
+ }
+ /* ouch: bsd and linux overlap. Don't even try for that partition */
+#ifdef DEBUG_BSD_DISKLABEL
+ printk("???: %d %ld+%ld,%d+%d",
+ lin_p - hd->part, lin_p->start_sect, lin_p->nr_sects,
+ bsd_p->p_offset, bsd_p->p_size);
+#endif
+ printk("???");
+ return;
+ } /* if the bsd partition is not currently known to linux, we end
+ * up here
+ */
+ add_gd_partition(hd, current_minor, bsd_p->p_offset, bsd_p->p_size);
+ current_minor++;
+}
+/*
+ * Create devices for BSD partitions listed in a disklabel, under a
+ * dos-like partition. See extended_partition() for more information.
+ */
+static void bsd_disklabel_partition(struct gendisk *hd, kdev_t dev,
+ int max_partitions)
+{
+ struct buffer_head *bh;
+ struct bsd_disklabel *l;
+ struct bsd_partition *p;
+ int mask = (1 << hd->minor_shift) - 1;
+
+ if (!(bh = bread(dev,0,get_ptable_blocksize(dev))))
+ return;
+ l = (struct bsd_disklabel *) (bh->b_data+512);
+ if (l->d_magic != BSD_DISKMAGIC) {
+ brelse(bh);
+ return;
+ }
+
+ if (l->d_npartitions < max_partitions)
+ max_partitions = l->d_npartitions;
+ for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) {
+ if ((current_minor & mask) >= (4 + hd->max_p))
+ break;
+
+ if (p->p_fstype != BSD_FS_UNUSED)
+ check_and_add_bsd_partition(hd, p, dev);
+ }
+
+ /* Use bforget(), as we have changed the disk setup */
+ bforget(bh);
+
+}
+#endif
+
+#ifdef CONFIG_UNIXWARE_DISKLABEL
+/*
+ * Create devices for Unixware partitions listed in a disklabel, under a
+ * dos-like partition. See extended_partition() for more information.
+ */
+static void unixware_partition(struct gendisk *hd, kdev_t dev)
+{
+ struct buffer_head *bh;
+ struct unixware_disklabel *l;
+ struct unixware_slice *p;
+ int mask = (1 << hd->minor_shift) - 1;
+
+ if (!(bh = bread(dev, 14, get_ptable_blocksize(dev))))
+ return;
+ l = (struct unixware_disklabel *) (bh->b_data+512);
+ if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
+ le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
+ brelse(bh);
+ return;
+ }
+ printk(" <unixware:");
+ p = &l->vtoc.v_slice[1];
+ /* I omit the 0th slice as it is the same as whole disk. */
+ while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
+ if ((current_minor & mask) == 0)
+ break;
+
+ if (p->s_label != UNIXWARE_FS_UNUSED) {
+ add_gd_partition(hd, current_minor, START_SECT(p), NR_SECTS(p));
+ current_minor++;
+ }
+ p++;
+ }
+ /* Use bforget, as we have changed the disk setup */
+ bforget(bh);
+ printk(" >");
+}
+#endif
+
+int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int first_part_minor)
+{
+ int i, minor = current_minor = first_part_minor;
+ struct buffer_head *bh;
+ struct partition *p;
+ unsigned char *data;
+ int mask = (1 << hd->minor_shift) - 1;
+ int sector_size = get_hardsect_size(dev) / 512;
+#ifdef CONFIG_BSD_DISKLABEL
+ /* no bsd disklabel as a default */
+ kdev_t bsd_kdev = 0;
+ int bsd_maxpart = BSD_MAXPARTITIONS;
+#endif
+#ifdef CONFIG_BLK_DEV_IDE
+ int tested_for_xlate = 0;
+
+read_mbr:
+#endif
+ if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) {
+ printk(" unable to read partition table\n");
+ return -1;
+ }
+ data = bh->b_data;
+#ifdef CONFIG_BLK_DEV_IDE
+check_table:
+#endif
+ /* Use bforget(), because we have potentially changed the disk geometry */
+ if (*(unsigned short *) (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
+ bforget(bh);
+ return 0;
+ }
+ p = (struct partition *) (0x1be + data);
+
+#ifdef CONFIG_BLK_DEV_IDE
+ if (!tested_for_xlate++) { /* Do this only once per disk */
+ /*
+ * Look for various forms of IDE disk geometry translation
+ */
+ extern int ide_xlate_1024(kdev_t, int, int, const char *);
+ unsigned int sig = le16_to_cpu(*(unsigned short *)(data + 2));
+ int heads = 0;
+ /*
+ * The i386 partition handling programs very often
+ * make partitions end on cylinder boundaries.
+ * There is no need to do so, and Linux fdisk doesnt always
+ * do this, and Windows NT on Alpha doesnt do this either,
+ * but still, this helps to guess #heads.
+ */
+ for (i = 0; i < 4; i++) {
+ struct partition *q = &p[i];
+ if (NR_SECTS(q)) {
+ if ((q->sector & 63) == 1 &&
+ (q->end_sector & 63) == 63)
+ heads = q->end_head + 1;
+ break;
+ }
+ }
+ if (SYS_IND(p) == EZD_PARTITION) {
+ /*
+ * Accesses to sector 0 must go to sector 1 instead.
+ */
+ if (ide_xlate_1024(dev, -1, heads, " [EZD]")) {
+ data += 512;
+ goto check_table;
+ }
+ } else if (SYS_IND(p) == DM6_PARTITION) {
+
+ /*
+ * Everything on the disk is offset by 63 sectors,
+ * including a "new" MBR with its own partition table.
+ */
+ if (ide_xlate_1024(dev, 1, heads, " [DM6:DDO]")) {
+ bforget(bh);
+ goto read_mbr; /* start over with new MBR */
+ }
+ } else if (sig <= 0x1ae &&
+ data[sig] == 0xAA && data[sig+1] == 0x55 &&
+ (data[sig+2] & 1)) {
+ /* DM6 signature in MBR, courtesy of OnTrack */
+ (void) ide_xlate_1024 (dev, 0, heads, " [DM6:MBR]");
+ } else if (SYS_IND(p) == DM6_AUX1PARTITION ||
+ SYS_IND(p) == DM6_AUX3PARTITION) {
+ /*
+ * DM6 on other than the first (boot) drive
+ */
+ (void) ide_xlate_1024(dev, 0, heads, " [DM6:AUX]");
+ } else {
+ (void) ide_xlate_1024(dev, 2, heads, " [PTBL]");
+ }
+ }
+#endif /* CONFIG_BLK_DEV_IDE */
+
+ current_minor += 4; /* first "extra" minor (for extended partitions) */
+ for (i=1 ; i<=4 ; minor++,i++,p++) {
+ if (!NR_SECTS(p))
+ continue;
+ add_gd_partition(hd, minor, first_sector+START_SECT(p)*sector_size, NR_SECTS(p)*sector_size);
+ if (is_extended_partition(p)) {
+ printk(" <");
+ /*
+ * If we are rereading the partition table, we need
+ * to set the size of the partition so that we will
+ * be able to bread the block containing the extended
+ * partition info.
+ */
+ hd->sizes[minor] = hd->part[minor].nr_sects
+ >> (BLOCK_SIZE_BITS - 9);
+ extended_partition(hd, MKDEV(hd->major, minor));
+ printk(" >");
+ /* prevent someone doing mkfs or mkswap on an
+ extended partition, but leave room for LILO */
+ if (hd->part[minor].nr_sects > 2)
+ hd->part[minor].nr_sects = 2;
+ }
+#ifdef CONFIG_BSD_DISKLABEL
+ /* tag first disklabel for late recognition */
+ if (SYS_IND(p) == BSD_PARTITION || SYS_IND(p) == NETBSD_PARTITION) {
+ printk("!");
+ if (!bsd_kdev)
+ bsd_kdev = MKDEV(hd->major, minor);
+ } else if (SYS_IND(p) == OPENBSD_PARTITION) {
+ printk("!");
+ if (!bsd_kdev) {
+ bsd_kdev = MKDEV(hd->major, minor);
+ bsd_maxpart = OPENBSD_MAXPARTITIONS;
+ }
+ }
+#endif
+#ifdef CONFIG_UNIXWARE_DISKLABEL
+ if (SYS_IND(p) == UNIXWARE_PARTITION)
+ unixware_partition(hd, MKDEV(hd->major, minor));
+#endif
+#ifdef CONFIG_SOLARIS_X86_PARTITION
+
+ /* james@bpgc.com: Solaris has a nasty indicator: 0x82
+ * which also means linux swap. For that reason, all
+ * of the prints are done inside the
+ * solaris_x86_partition routine */
+
+ if(SYS_IND(p) == SOLARIS_X86_PARTITION) {
+ solaris_x86_partition(hd, MKDEV(hd->major, minor),
+ first_sector+START_SECT(p));
+ }
+#endif
+ }
+#ifdef CONFIG_BSD_DISKLABEL
+ if (bsd_kdev) {
+ printk(" <");
+ bsd_disklabel_partition(hd, bsd_kdev, bsd_maxpart);
+ printk(" >");
+ }
+#endif
+ /*
+ * Check for old-style Disk Manager partition table
+ */
+ if (*(unsigned short *) (data+0xfc) == cpu_to_le16(MSDOS_LABEL_MAGIC)) {
+ p = (struct partition *) (0x1be + data);
+ for (i = 4 ; i < 16 ; i++, current_minor++) {
+ p--;
+ if ((current_minor & mask) == 0)
+ break;
+ if (!(START_SECT(p) && NR_SECTS(p)))
+ continue;
+ add_gd_partition(hd, current_minor, START_SECT(p), NR_SECTS(p));
+ }
+ }
+ printk("\n");
+ bforget(bh);
+ return 1;
+}
diff --git a/fs/partitions/msdos.h b/fs/partitions/msdos.h
new file mode 100644
index 000000000..e24740c5e
--- /dev/null
+++ b/fs/partitions/msdos.h
@@ -0,0 +1,9 @@
+/*
+ * fs/partitions/msdos.h
+ */
+
+#define MSDOS_LABEL_MAGIC 0xAA55
+
+int msdos_partition(struct gendisk *hd, kdev_t dev,
+ unsigned long first_sector, int first_part_minor);
+
diff --git a/fs/partitions/osf.c b/fs/partitions/osf.c
new file mode 100644
index 000000000..6cd1540c0
--- /dev/null
+++ b/fs/partitions/osf.c
@@ -0,0 +1,86 @@
+/*
+ * fs/partitions/osf.c
+ *
+ * Code extracted from drivers/block/genhd.c
+ *
+ * Copyright (C) 1991-1998 Linus Torvalds
+ * Re-organised Feb 1998 Russell King
+ */
+
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+
+#include "check.h"
+#include "osf.h"
+
+int osf_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
+ int current_minor)
+{
+ int i;
+ int mask = (1 << hd->minor_shift) - 1;
+ struct buffer_head *bh;
+ struct disklabel {
+ u32 d_magic;
+ u16 d_type,d_subtype;
+ u8 d_typename[16];
+ u8 d_packname[16];
+ u32 d_secsize;
+ u32 d_nsectors;
+ u32 d_ntracks;
+ u32 d_ncylinders;
+ u32 d_secpercyl;
+ u32 d_secprtunit;
+ u16 d_sparespertrack;
+ u16 d_sparespercyl;
+ u32 d_acylinders;
+ u16 d_rpm, d_interleave, d_trackskew, d_cylskew;
+ u32 d_headswitch, d_trkseek, d_flags;
+ u32 d_drivedata[5];
+ u32 d_spare[5];
+ u32 d_magic2;
+ u16 d_checksum;
+ u16 d_npartitions;
+ u32 d_bbsize, d_sbsize;
+ struct d_partition {
+ u32 p_size;
+ u32 p_offset;
+ u32 p_fsize;
+ u8 p_fstype;
+ u8 p_frag;
+ u16 p_cpg;
+ } d_partitions[8];
+ } * label;
+ struct d_partition * partition;
+
+ if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) {
+ printk("unable to read partition table\n");
+ return -1;
+ }
+ label = (struct disklabel *) (bh->b_data+64);
+ partition = label->d_partitions;
+ if (label->d_magic != DISKLABELMAGIC) {
+ brelse(bh);
+ return 0;
+ }
+ if (label->d_magic2 != DISKLABELMAGIC) {
+ brelse(bh);
+ return 0;
+ }
+ for (i = 0 ; i < label->d_npartitions; i++, partition++) {
+ if ((current_minor & mask) == 0)
+ break;
+ if (partition->p_size)
+ add_gd_partition(hd, current_minor,
+ first_sector+partition->p_offset,
+ partition->p_size);
+ current_minor++;
+ }
+ printk("\n");
+ brelse(bh);
+ return 1;
+}
+
diff --git a/fs/partitions/osf.h b/fs/partitions/osf.h
new file mode 100644
index 000000000..ce1415056
--- /dev/null
+++ b/fs/partitions/osf.h
@@ -0,0 +1,9 @@
+/*
+ * fs/partitions/osf.h
+ */
+
+#define DISKLABELMAGIC (0x82564557UL)
+
+int osf_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
+ int current_minor);
+
diff --git a/fs/partitions/sgi.c b/fs/partitions/sgi.c
new file mode 100644
index 000000000..8ae97eca0
--- /dev/null
+++ b/fs/partitions/sgi.c
@@ -0,0 +1,86 @@
+/*
+ * fs/partitions/sgi.c
+ *
+ * Code extracted from drivers/block/genhd.c
+ */
+
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+
+#include "check.h"
+#include "sgi.h"
+
+int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int first_part_minor)
+{
+ int i, csum, magic, current_minor = first_part_minor;
+ unsigned int *ui, start, blocks, cs;
+ struct buffer_head *bh;
+ struct sgi_disklabel {
+ int magic_mushroom; /* Big fat spliff... */
+ short root_part_num; /* Root partition number */
+ short swap_part_num; /* Swap partition number */
+ char boot_file[16]; /* Name of boot file for ARCS */
+ unsigned char _unused0[48]; /* Device parameter useless crapola.. */
+ struct sgi_volume {
+ char name[8]; /* Name of volume */
+ int block_num; /* Logical block number */
+ int num_bytes; /* How big, in bytes */
+ } volume[15];
+ struct sgi_partition {
+ int num_blocks; /* Size in logical blocks */
+ int first_block; /* First logical block */
+ int type; /* Type of this partition */
+ } partitions[16];
+ int csum; /* Disk label checksum */
+ int _unused1; /* Padding */
+ } *label;
+ struct sgi_partition *p;
+
+ if(!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) {
+ printk("Dev %s: unable to read partition table\n", kdevname(dev));
+ return -1;
+ }
+ label = (struct sgi_disklabel *) bh->b_data;
+ p = &label->partitions[0];
+ magic = label->magic_mushroom;
+ if(be32_to_cpu(magic) != SGI_LABEL_MAGIC) {
+ printk("Dev %s SGI disklabel: bad magic %08x\n",
+ kdevname(dev), magic);
+ brelse(bh);
+ return 0;
+ }
+ ui = ((unsigned int *) (label + 1)) - 1;
+ for(csum = 0; ui >= ((unsigned int *) label);) {
+ cs = *ui--;
+ csum += be32_to_cpu(cs);
+ }
+ if(csum) {
+ printk("Dev %s SGI disklabel: csum bad, label corrupted\n",
+ kdevname(dev));
+ brelse(bh);
+ return 0;
+ }
+ /* All SGI disk labels have 16 partitions, disks under Linux only
+ * have 15 minor's. Luckily there are always a few zero length
+ * partitions which we don't care about so we never overflow the
+ * current_minor.
+ */
+ for(i = 0; i < 16; i++, p++) {
+ blocks = be32_to_cpu(p->num_blocks);
+ start = be32_to_cpu(p->first_block);
+ if(!blocks)
+ continue;
+ add_gd_partition(hd, current_minor, start, blocks);
+ current_minor++;
+ }
+ printk("\n");
+ brelse(bh);
+ return 1;
+}
diff --git a/fs/partitions/sgi.h b/fs/partitions/sgi.h
new file mode 100644
index 000000000..6e4ac1ac4
--- /dev/null
+++ b/fs/partitions/sgi.h
@@ -0,0 +1,9 @@
+/*
+ * fs/partitions/sgi.h
+ */
+
+extern int sgi_partition(struct gendisk *hd, kdev_t dev,
+ unsigned long first_sector, int first_part_minor);
+
+#define SGI_LABEL_MAGIC 0x0be5a941
+
diff --git a/fs/partitions/sun.c b/fs/partitions/sun.c
new file mode 100644
index 000000000..5d82a70c6
--- /dev/null
+++ b/fs/partitions/sun.c
@@ -0,0 +1,89 @@
+/*
+ * fs/partitions/sun.c
+ *
+ * Code extracted from drivers/block/genhd.c
+ *
+ * Copyright (C) 1991-1998 Linus Torvalds
+ * Re-organised Feb 1998 Russell King
+ */
+
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+
+#include <asm/system.h>
+
+#include "check.h"
+#include "sun.h"
+
+int sun_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int first_part_minor)
+{
+ int i, csum;
+ unsigned short *ush;
+ struct buffer_head *bh;
+ struct sun_disklabel {
+ unsigned char info[128]; /* Informative text string */
+ unsigned char spare[292]; /* Boot information etc. */
+ unsigned short rspeed; /* Disk rotational speed */
+ unsigned short pcylcount; /* Physical cylinder count */
+ unsigned short sparecyl; /* extra sects per cylinder */
+ unsigned char spare2[4]; /* More magic... */
+ unsigned short ilfact; /* Interleave factor */
+ unsigned short ncyl; /* Data cylinder count */
+ unsigned short nacyl; /* Alt. cylinder count */
+ unsigned short ntrks; /* Tracks per cylinder */
+ unsigned short nsect; /* Sectors per track */
+ unsigned char spare3[4]; /* Even more magic... */
+ struct sun_partition {
+ __u32 start_cylinder;
+ __u32 num_sectors;
+ } partitions[8];
+ unsigned short magic; /* Magic number */
+ unsigned short csum; /* Label xor'd checksum */
+ } * label;
+ struct sun_partition *p;
+ unsigned long spc;
+
+ if(!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) {
+ printk("Dev %s: unable to read partition table\n",
+ kdevname(dev));
+ return -1;
+ }
+ label = (struct sun_disklabel *) bh->b_data;
+ p = label->partitions;
+ if (be16_to_cpu(label->magic) != SUN_LABEL_MAGIC) {
+ printk("Dev %s Sun disklabel: bad magic %04x\n",
+ kdevname(dev), be16_to_cpu(label->magic));
+ brelse(bh);
+ return 0;
+ }
+ /* Look at the checksum */
+ ush = ((unsigned short *) (label+1)) - 1;
+ for(csum = 0; ush >= ((unsigned short *) label);)
+ csum ^= *ush--;
+ if(csum) {
+ printk("Dev %s Sun disklabel: Csum bad, label corrupted\n",
+ kdevname(dev));
+ brelse(bh);
+ return 0;
+ }
+ /* All Sun disks have 8 partition entries */
+ spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
+ for(i=0; i < 8; i++, p++) {
+ unsigned long st_sector;
+ int num_sectors;
+
+ st_sector = first_sector + be32_to_cpu(p->start_cylinder) * spc;
+ num_sectors = be32_to_cpu(p->num_sectors);
+ if (num_sectors)
+ add_gd_partition(hd, first_part_minor, st_sector, num_sectors);
+ first_part_minor++;
+ }
+ printk("\n");
+ brelse(bh);
+ return 1;
+}
+
diff --git a/fs/partitions/sun.h b/fs/partitions/sun.h
new file mode 100644
index 000000000..3426d4aa2
--- /dev/null
+++ b/fs/partitions/sun.h
@@ -0,0 +1,9 @@
+/*
+ * fs/partitions/sun.h
+ */
+
+#define SUN_LABEL_MAGIC 0xDABE
+
+int sun_partition(struct gendisk *hd, kdev_t dev,
+ unsigned long first_sector, int first_part_minor);
+
diff --git a/fs/partitions/ultrix.c b/fs/partitions/ultrix.c
new file mode 100644
index 000000000..fcfaf0d22
--- /dev/null
+++ b/fs/partitions/ultrix.c
@@ -0,0 +1,60 @@
+/*
+ * fs/partitions/ultrix.c
+ *
+ * Code extracted from drivers/block/genhd.c
+ *
+ * Re-organised Jul 1999 Russell King
+ */
+
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+
+#include "check.h"
+
+static int ultrix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
+{
+ int i, minor = current_minor;
+ struct buffer_head *bh;
+ struct ultrix_disklabel {
+ s32 pt_magic; /* magic no. indicating part. info exits */
+ s32 pt_valid; /* set by driver if pt is current */
+ struct pt_info {
+ s32 pi_nblocks; /* no. of sectors */
+ u32 pi_blkoff; /* block offset for start */
+ } pt_part[8];
+ } *label;
+
+#define PT_MAGIC 0x032957 /* Partition magic number */
+#define PT_VALID 1 /* Indicates if struct is valid */
+
+#define SBLOCK ((unsigned long)((16384 - sizeof(struct ultrix_disklabel)) \
+ /get_ptable_blocksize(dev)))
+
+ bh = bread (dev, SBLOCK, get_ptable_blocksize(dev));
+ if (!bh) {
+ printk (" unable to read block 0x%lx\n", SBLOCK);
+ return -1;
+ }
+
+ label = (struct ultrix_disklabel *)(bh->b_data
+ + get_ptable_blocksize(dev)
+ - sizeof(struct ultrix_disklabel));
+
+ if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) {
+ for (i=0; i<8; i++, minor++)
+ if (label->pt_part[i].pi_nblocks)
+ add_gd_partition(hd, minor,
+ label->pt_part[i].pi_blkoff,
+ label->pt_part[i].pi_nblocks);
+ brelse(bh);
+ printk ("\n");
+ return 1;
+ } else {
+ brelse(bh);
+ return 0;
+ }
+}
+
diff --git a/fs/pipe.c b/fs/pipe.c
index 2303ca328..7cdd2b394 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1,7 +1,7 @@
/*
* linux/fs/pipe.c
*
- * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1991, 1992, 1999 Linus Torvalds
*/
#include <linux/mm.h>
@@ -22,187 +22,258 @@
#undef FIFO_SUNOS_BRAINDAMAGE
#endif
-/* We don't use the head/tail construction any more. Now we use the start/len*/
-/* construction providing full use of PIPE_BUF (multiple of PAGE_SIZE) */
-/* Florian Coosmann (FGC) ^ current = 1 */
-/* Additionally, we now use locking technique. This prevents race condition */
-/* in case of paging and multiple read/write on the same pipe. (FGC) */
-/* Reads with count = 0 should always return 0. Julian Bradfield 1999-06-07. */
+/*
+ * We use a start+len construction, which provides full use of the
+ * allocated memory.
+ * -- Florian Coosmann (FGC)
+ *
+ * Reads with count = 0 should always return 0.
+ * -- Julian Bradfield 1999-06-07.
+ */
-static ssize_t do_pipe_read(struct file * filp, char * buf, size_t count)
+/* Drop the inode semaphore and wait for a pipe event, atomically */
+static void pipe_wait(struct inode * inode)
{
- struct inode * inode = filp->f_dentry->d_inode;
- ssize_t chars = 0, size = 0, read = 0;
- char *pipebuf;
+ DECLARE_WAITQUEUE(wait, current);
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(PIPE_WAIT(*inode), &wait);
+ up(PIPE_SEM(*inode));
+ schedule();
+ remove_wait_queue(PIPE_WAIT(*inode), &wait);
+ current->state = TASK_RUNNING;
+}
- if (filp->f_flags & O_NONBLOCK) {
- if (PIPE_LOCK(*inode))
- return -EAGAIN;
- if (PIPE_EMPTY(*inode)) {
- if (PIPE_WRITERS(*inode))
- return -EAGAIN;
- else
- return 0;
- }
- } else while (PIPE_EMPTY(*inode) || PIPE_LOCK(*inode)) {
- if (PIPE_EMPTY(*inode)) {
- if (!PIPE_WRITERS(*inode) || !count)
- return 0;
+static ssize_t
+pipe_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ ssize_t size, read, ret;
+
+ /* Seeks are not allowed on pipes. */
+ ret = -ESPIPE;
+ if (ppos != &filp->f_pos)
+ goto out_nolock;
+
+ /* Always return 0 on null read. */
+ ret = 0;
+ if (count == 0)
+ goto out_nolock;
+
+ /* Get the pipe semaphore */
+ ret = -ERESTARTSYS;
+ if (down_interruptible(PIPE_SEM(*inode)))
+ goto out_nolock;
+
+ if (PIPE_EMPTY(*inode)) {
+ ret = 0;
+ if (!PIPE_WRITERS(*inode))
+ goto out;
+
+ ret = -EAGAIN;
+ if (filp->f_flags & O_NONBLOCK)
+ goto out;
+
+ for (;;) {
+ pipe_wait(inode);
+ ret = -ERESTARTSYS;
+ if (signal_pending(current))
+ goto out_nolock;
+ if (down_interruptible(PIPE_SEM(*inode)))
+ goto out_nolock;
+ ret = 0;
+ if (!PIPE_EMPTY(*inode))
+ break;
+ if (!PIPE_WRITERS(*inode))
+ goto out;
}
- if (signal_pending(current))
- return -ERESTARTSYS;
- interruptible_sleep_on(&PIPE_WAIT(*inode));
}
- PIPE_LOCK(*inode)++;
- while (count>0 && (size = PIPE_SIZE(*inode))) {
- chars = PIPE_MAX_RCHUNK(*inode);
+
+ /* Read what data is available. */
+ ret = -EFAULT;
+ read = 0;
+ while (count > 0 && (size = PIPE_LEN(*inode))) {
+ char *pipebuf = PIPE_BASE(*inode) + PIPE_START(*inode);
+ ssize_t chars = PIPE_MAX_RCHUNK(*inode);
+
if (chars > count)
chars = count;
if (chars > size)
chars = size;
+
+ if (copy_to_user(buf, pipebuf, chars))
+ goto out;
+
read += chars;
- pipebuf = PIPE_BASE(*inode)+PIPE_START(*inode);
PIPE_START(*inode) += chars;
- PIPE_START(*inode) &= (PIPE_BUF-1);
+ PIPE_START(*inode) &= (PIPE_SIZE - 1);
PIPE_LEN(*inode) -= chars;
count -= chars;
- copy_to_user(buf, pipebuf, chars );
buf += chars;
}
- PIPE_LOCK(*inode)--;
- wake_up_interruptible(&PIPE_WAIT(*inode));
- if (read) {
+
+ /* Cache behaviour optimization */
+ if (!PIPE_LEN(*inode))
+ PIPE_START(*inode) = 0;
+
+ /* Signal writers there is more room. */
+ wake_up_interruptible(PIPE_WAIT(*inode));
+
+ if (read)
UPDATE_ATIME(inode);
- return read;
- }
- if (PIPE_WRITERS(*inode))
- return -EAGAIN;
- return 0;
+ ret = read;
+
+out:
+ up(PIPE_SEM(*inode));
+out_nolock:
+ return ret;
}
-static ssize_t do_pipe_write(struct file * filp, const char * buf, size_t count)
+static ssize_t
+pipe_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
{
- struct inode * inode = filp->f_dentry->d_inode;
- ssize_t chars = 0, free = 0, written = 0, err=0;
- char *pipebuf;
+ struct inode *inode = filp->f_dentry->d_inode;
+ ssize_t free, written, ret;
- if (!PIPE_READERS(*inode)) { /* no readers */
- send_sig(SIGPIPE,current,0);
- return -EPIPE;
- }
- /* if count <= PIPE_BUF, we have to make it atomic */
- if (count <= PIPE_BUF)
- free = count;
- else
- free = 1; /* can't do it atomically, wait for any free space */
- if (down_interruptible(&inode->i_sem)) {
- return -ERESTARTSYS;
- }
- while (count>0) {
- while ((PIPE_FREE(*inode) < free) || PIPE_LOCK(*inode)) {
- if (!PIPE_READERS(*inode)) { /* no readers */
- send_sig(SIGPIPE,current,0);
- err = -EPIPE;
- goto errout;
- }
- if (signal_pending(current)) {
- err = -ERESTARTSYS;
- goto errout;
- }
- if (filp->f_flags & O_NONBLOCK) {
- err = -EAGAIN;
- goto errout;
- }
- interruptible_sleep_on(&PIPE_WAIT(*inode));
+ /* Seeks are not allowed on pipes. */
+ ret = -ESPIPE;
+ if (ppos != &filp->f_pos)
+ goto out_nolock;
+
+ /* Null write succeeds. */
+ ret = 0;
+ if (count == 0)
+ goto out_nolock;
+
+ ret = -ERESTARTSYS;
+ if (down_interruptible(PIPE_SEM(*inode)))
+ goto out_nolock;
+
+ /* No readers yields SIGPIPE. */
+ if (!PIPE_READERS(*inode))
+ goto sigpipe;
+
+ /* If count <= PIPE_BUF, we have to make it atomic. */
+ free = (count <= PIPE_BUF ? count : 1);
+ written = 0;
+
+ /* Wait, or check for, available space. */
+ if (filp->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ if (PIPE_FREE(*inode) < free)
+ goto out;
+ } else {
+ while (PIPE_FREE(*inode) < free) {
+ pipe_wait(inode);
+ ret = -ERESTARTSYS;
+ if (signal_pending(current))
+ goto out_nolock;
+ if (down_interruptible(PIPE_SEM(*inode)))
+ goto out_nolock;
+
+ if (!PIPE_READERS(*inode))
+ goto sigpipe;
}
- PIPE_LOCK(*inode)++;
- while (count>0 && (free = PIPE_FREE(*inode))) {
- chars = PIPE_MAX_WCHUNK(*inode);
+ }
+
+ /* Copy into available space. */
+ ret = -EFAULT;
+ while (count > 0) {
+ int space;
+ char *pipebuf = PIPE_BASE(*inode) + PIPE_END(*inode);
+ ssize_t chars = PIPE_MAX_WCHUNK(*inode);
+
+ if ((space = PIPE_FREE(*inode)) != 0) {
if (chars > count)
chars = count;
- if (chars > free)
- chars = free;
- pipebuf = PIPE_BASE(*inode)+PIPE_END(*inode);
+ if (chars > space)
+ chars = space;
+
+ if (copy_from_user(pipebuf, buf, chars))
+ goto out;
+
written += chars;
PIPE_LEN(*inode) += chars;
count -= chars;
- copy_from_user(pipebuf, buf, chars );
buf += chars;
+ space = PIPE_FREE(*inode);
+ continue;
}
- PIPE_LOCK(*inode)--;
- wake_up_interruptible(&PIPE_WAIT(*inode));
- free = 1;
- }
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- mark_inode_dirty(inode);
-errout:
- up(&inode->i_sem);
- return written ? written : err;
-}
-static ssize_t pipe_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
-{
- ssize_t retval;
-
-
- if (ppos != &filp->f_pos)
- return -ESPIPE;
-
- if ( !count ) return 0;
+ ret = written;
+ if (filp->f_flags & O_NONBLOCK)
+ break;
+
+ do {
+ /* This should be a synchronous wake-up: don't do idle reschedules! */
+ wake_up_interruptible(PIPE_WAIT(*inode));
+ pipe_wait(inode);
+ if (signal_pending(current))
+ goto out_nolock;
+ if (down_interruptible(PIPE_SEM(*inode)))
+ goto out_nolock;
+ if (!PIPE_READERS(*inode))
+ goto sigpipe;
+ } while (!PIPE_FREE(*inode));
+ ret = -EFAULT;
+ }
- lock_kernel();
- retval = do_pipe_read(filp, buf, count);
- unlock_kernel();
- return retval;
-}
+ /* Signal readers there is more data. */
+ wake_up_interruptible(PIPE_WAIT(*inode));
-static ssize_t pipe_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
-{
- ssize_t retval;
+ ret = (written ? written : -EAGAIN);
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(inode);
- if (ppos != &filp->f_pos)
- return -ESPIPE;
+out:
+ up(PIPE_SEM(*inode));
+out_nolock:
+ return ret;
- lock_kernel();
- retval = do_pipe_write(filp, buf, count);
- unlock_kernel();
- return retval;
+sigpipe:
+ up(PIPE_SEM(*inode));
+ send_sig(SIGPIPE, current, 0);
+ return -EPIPE;
}
-static long long pipe_lseek(struct file * file, long long offset, int orig)
+static loff_t
+pipe_lseek(struct file *file, loff_t offset, int orig)
{
return -ESPIPE;
}
-static ssize_t bad_pipe_r(struct file * filp, char * buf,
- size_t count, loff_t *ppos)
+static ssize_t
+bad_pipe_r(struct file *filp, char *buf, size_t count, loff_t *ppos)
{
return -EBADF;
}
-static ssize_t bad_pipe_w(struct file * filp, const char * buf,
- size_t count, loff_t *ppos)
+static ssize_t
+bad_pipe_w(struct file *filp, const char *buf, size_t count, loff_t *ppos)
{
return -EBADF;
}
-static int pipe_ioctl(struct inode *pino, struct file * filp,
- unsigned int cmd, unsigned long arg)
+static int
+pipe_ioctl(struct inode *pino, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case FIONREAD:
- return put_user(PIPE_SIZE(*pino),(int *) arg);
+ return put_user(PIPE_LEN(*pino), (int *)arg);
default:
return -EINVAL;
}
}
-static unsigned int pipe_poll(struct file * filp, poll_table * wait)
+static unsigned int
+pipe_poll(struct file *filp, poll_table *wait)
{
unsigned int mask;
- struct inode * inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_dentry->d_inode;
+
+ poll_wait(filp, PIPE_WAIT(*inode), wait);
- poll_wait(filp, &PIPE_WAIT(*inode), wait);
+ /* Reading only -- no need for aquiring the semaphore. */
mask = POLLIN | POLLRDNORM;
if (PIPE_EMPTY(*inode))
mask = POLLOUT | POLLWRNORM;
@@ -210,6 +281,7 @@ static unsigned int pipe_poll(struct file * filp, poll_table * wait)
mask |= POLLHUP;
if (!PIPE_READERS(*inode))
mask |= POLLERR;
+
return mask;
}
@@ -218,17 +290,21 @@ static unsigned int pipe_poll(struct file * filp, poll_table * wait)
* Argh! Why does SunOS have to have different select() behaviour
* for pipes and FIFOs? Hate, hate, hate! SunOS lacks POLLHUP.
*/
-static unsigned int fifo_poll(struct file * filp, poll_table * wait)
+static unsigned int
+fifo_poll(struct file *filp, poll_table *wait)
{
unsigned int mask;
- struct inode * inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_dentry->d_inode;
+
+ poll_wait(filp, PIPE_WAIT(*inode), wait);
- poll_wait(filp, &PIPE_WAIT(*inode), wait);
+ /* Reading only -- no need for aquiring the semaphore. */
mask = POLLIN | POLLRDNORM;
if (PIPE_EMPTY(*inode))
mask = POLLOUT | POLLWRNORM;
if (!PIPE_READERS(*inode))
mask |= POLLERR;
+
return mask;
}
#else
@@ -242,82 +318,112 @@ static unsigned int fifo_poll(struct file * filp, poll_table * wait)
* the open() code hasn't guaranteed a connection (O_NONBLOCK),
* and we need to act differently until we do get a writer..
*/
-static ssize_t connect_read(struct file * filp, char * buf,
- size_t count, loff_t *ppos)
+static ssize_t
+connect_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
{
- struct inode * inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_dentry->d_inode;
+
+ /* Reading only -- no need for aquiring the semaphore. */
if (PIPE_EMPTY(*inode) && !PIPE_WRITERS(*inode))
return 0;
+
filp->f_op = &read_fifo_fops;
- return pipe_read(filp,buf,count,ppos);
+ return pipe_read(filp, buf, count, ppos);
}
-static unsigned int connect_poll(struct file * filp, poll_table * wait)
+static unsigned int
+connect_poll(struct file *filp, poll_table *wait)
{
- struct inode * inode = filp->f_dentry->d_inode;
+ struct inode *inode = filp->f_dentry->d_inode;
+ unsigned int mask = 0;
+
+ poll_wait(filp, PIPE_WAIT(*inode), wait);
- poll_wait(filp, &PIPE_WAIT(*inode), wait);
+ /* Reading only -- no need for aquiring the semaphore. */
if (!PIPE_EMPTY(*inode)) {
filp->f_op = &read_fifo_fops;
- return POLLIN | POLLRDNORM;
- }
- if (PIPE_WRITERS(*inode))
+ mask = POLLIN | POLLRDNORM;
+ } else if (PIPE_WRITERS(*inode)) {
filp->f_op = &read_fifo_fops;
- return POLLOUT | POLLWRNORM;
+ mask = POLLOUT | POLLWRNORM;
+ }
+
+ return mask;
}
-static int pipe_release(struct inode * inode)
+static int
+pipe_release(struct inode *inode, int decr, int decw)
{
+ down(PIPE_SEM(*inode));
+ PIPE_READERS(*inode) -= decr;
+ PIPE_WRITERS(*inode) -= decw;
if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) {
struct pipe_inode_info *info = inode->i_pipe;
inode->i_pipe = NULL;
free_page((unsigned long) info->base);
kfree(info);
- return 0;
+ } else {
+ wake_up_interruptible(PIPE_WAIT(*inode));
}
- wake_up_interruptible(&PIPE_WAIT(*inode));
+ up(PIPE_SEM(*inode));
+
return 0;
}
-static int pipe_read_release(struct inode * inode, struct file * filp)
+static int
+pipe_read_release(struct inode *inode, struct file *filp)
{
- PIPE_READERS(*inode)--;
- return pipe_release(inode);
+ return pipe_release(inode, 1, 0);
}
-static int pipe_write_release(struct inode * inode, struct file * filp)
+static int
+pipe_write_release(struct inode *inode, struct file *filp)
{
- PIPE_WRITERS(*inode)--;
- return pipe_release(inode);
+ return pipe_release(inode, 0, 1);
}
-static int pipe_rdwr_release(struct inode * inode, struct file * filp)
+static int
+pipe_rdwr_release(struct inode *inode, struct file *filp)
{
- if (filp->f_mode & FMODE_READ)
- PIPE_READERS(*inode)--;
- if (filp->f_mode & FMODE_WRITE)
- PIPE_WRITERS(*inode)--;
- return pipe_release(inode);
+ int decr, decw;
+
+ decr = (filp->f_mode & FMODE_READ) != 0;
+ decw = (filp->f_mode & FMODE_WRITE) != 0;
+ return pipe_release(inode, decr, decw);
}
-static int pipe_read_open(struct inode * inode, struct file * filp)
+static int
+pipe_read_open(struct inode *inode, struct file *filp)
{
+ /* We could have perhaps used atomic_t, but this and friends
+ below are the only places. So it doesn't seem worthwhile. */
+ down(PIPE_SEM(*inode));
PIPE_READERS(*inode)++;
+ up(PIPE_SEM(*inode));
+
return 0;
}
-static int pipe_write_open(struct inode * inode, struct file * filp)
+static int
+pipe_write_open(struct inode *inode, struct file *filp)
{
+ down(PIPE_SEM(*inode));
PIPE_WRITERS(*inode)++;
+ up(PIPE_SEM(*inode));
+
return 0;
}
-static int pipe_rdwr_open(struct inode * inode, struct file * filp)
+static int
+pipe_rdwr_open(struct inode *inode, struct file *filp)
{
+ down(PIPE_SEM(*inode));
if (filp->f_mode & FMODE_READ)
PIPE_READERS(*inode)++;
if (filp->f_mode & FMODE_WRITE)
PIPE_WRITERS(*inode)++;
+ up(PIPE_SEM(*inode));
+
return 0;
}
@@ -433,22 +539,20 @@ static struct inode * get_pipe_inode(void)
goto fail_inode;
page = __get_free_page(GFP_USER);
-
if (!page)
goto fail_iput;
- /* XXX */
inode->i_pipe = kmalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
if (!inode->i_pipe)
goto fail_page;
- PIPE_BASE(*inode) = (char *) page;
inode->i_op = &pipe_inode_operations;
- init_waitqueue_head(&PIPE_WAIT(*inode));
+
+ init_waitqueue_head(PIPE_WAIT(*inode));
+ PIPE_BASE(*inode) = (char *) page;
PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
- PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
- PIPE_LOCK(*inode) = 0;
+
/*
* Mark the inode dirty from the very beginning,
* that way it will never be moved to the dirty
diff --git a/fs/proc/array.c b/fs/proc/array.c
index f108511fb..e2775ae0d 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -42,6 +42,10 @@
* Alan Cox : security fixes.
* <Alan.Cox@linux.org>
*
+ * Al Viro : safe handling of mm_struct
+ *
+ * Gerhard Wichert : added BIGMEM support
+ * Siemens AG <Gerhard.Wichert@pdb.siemens.de>
*/
#include <linux/types.h>
@@ -76,6 +80,11 @@ int get_malloc(char * buffer);
#endif
+static int open_kcore(struct inode * inode, struct file * filp)
+{
+ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
static ssize_t read_core(struct file * file, char * buf,
size_t count, loff_t *ppos)
{
@@ -93,6 +102,9 @@ static ssize_t read_core(struct file * file, char * buf,
memset(&dump, 0, sizeof(struct user));
dump.magic = CMAGIC;
dump.u_dsize = max_mapnr;
+#if defined (__i386__)
+ dump.start_code = PAGE_OFFSET;
+#endif
#ifdef __alpha__
dump.start_data = PAGE_OFFSET;
#endif
@@ -137,6 +149,12 @@ static ssize_t read_core(struct file * file, char * buf,
static struct file_operations proc_kcore_operations = {
NULL, /* lseek */
read_core,
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ open_kcore
};
struct inode_operations proc_kcore_inode_operations = {
@@ -223,7 +241,7 @@ static int get_loadavg(char * buffer)
LOAD_INT(a), LOAD_FRAC(a),
LOAD_INT(b), LOAD_FRAC(b),
LOAD_INT(c), LOAD_FRAC(c),
- nr_running, nr_tasks, last_pid);
+ nr_running, nr_threads, last_pid);
}
static int get_kstat(char * buffer)
@@ -231,9 +249,8 @@ static int get_kstat(char * buffer)
int i, len;
unsigned sum = 0;
extern unsigned long total_forks;
- unsigned long ticks;
+ unsigned long jif = HZ_TO_STD(jiffies);
- ticks = HZ_TO_STD(jiffies) * smp_num_cpus;
for (i = 0 ; i < NR_IRQS ; i++)
sum += kstat_irqs(i);
@@ -243,14 +260,14 @@ static int get_kstat(char * buffer)
kstat.cpu_user,
kstat.cpu_nice,
kstat.cpu_system,
- jiffies*smp_num_cpus - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system));
+ jif*smp_num_cpus - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
for (i = 0 ; i < smp_num_cpus; i++)
len += sprintf(buffer + len, "cpu%d %u %u %u %lu\n",
i,
kstat.per_cpu_user[cpu_logical_map(i)],
kstat.per_cpu_nice[cpu_logical_map(i)],
kstat.per_cpu_system[cpu_logical_map(i)],
- jiffies - ( kstat.per_cpu_user[cpu_logical_map(i)] \
+ jif - ( kstat.per_cpu_user[cpu_logical_map(i)] \
+ kstat.per_cpu_nice[cpu_logical_map(i)] \
+ kstat.per_cpu_system[cpu_logical_map(i)]));
len += sprintf(buffer + len,
@@ -276,7 +293,7 @@ static int get_kstat(char * buffer)
HZ_TO_STD(kstat.cpu_user),
HZ_TO_STD(kstat.cpu_nice),
HZ_TO_STD(kstat.cpu_system),
- ticks - HZ_TO_STD(kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
+ jif*smp_num_cpus - HZ_TO_STD(kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
#endif
kstat.dk_drive[0], kstat.dk_drive[1],
kstat.dk_drive[2], kstat.dk_drive[3],
@@ -300,7 +317,7 @@ static int get_kstat(char * buffer)
"btime %lu\n"
"processes %lu\n",
kstat.context_swtch,
- xtime.tv_sec - jiffies / HZ,
+ xtime.tv_sec - jif / HZ,
total_forks);
return len;
}
@@ -312,7 +329,7 @@ static int get_uptime(char * buffer)
unsigned long idle;
uptime = jiffies;
- idle = task[0]->times.tms_utime + task[0]->times.tms_stime;
+ idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
/* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
that would overflow about every five days at HZ == 100.
@@ -348,7 +365,7 @@ static int get_meminfo(char * buffer)
len = sprintf(buffer, " total: used: free: shared: buffers: cached:\n"
"Mem: %8lu %8lu %8lu %8lu %8lu %8lu\n"
"Swap: %8lu %8lu %8lu\n",
- i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, atomic_read(&page_cache_size)*PAGE_SIZE,
+ i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, (unsigned long) atomic_read(&page_cache_size)*PAGE_SIZE,
i.totalswap, i.totalswap-i.freeswap, i.freeswap);
/*
* Tagged format, for easy grepping and expansion. The above will go away
@@ -360,6 +377,8 @@ static int get_meminfo(char * buffer)
"MemShared: %8lu kB\n"
"Buffers: %8lu kB\n"
"Cached: %8u kB\n"
+ "BigTotal: %8lu kB\n"
+ "BigFree: %8lu kB\n"
"SwapTotal: %8lu kB\n"
"SwapFree: %8lu kB\n",
i.totalram >> 10,
@@ -367,6 +386,8 @@ static int get_meminfo(char * buffer)
i.sharedram >> 10,
i.bufferram >> 10,
atomic_read(&page_cache_size) << (PAGE_SHIFT - 10),
+ i.totalbig >> 10,
+ i.freebig >> 10,
i.totalswap >> 10,
i.freeswap >> 10);
}
@@ -386,21 +407,15 @@ static int get_cmdline(char * buffer)
return sprintf(buffer, "%s\n", saved_command_line);
}
-static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
+static unsigned long get_phys_addr(struct mm_struct * mm, unsigned long ptr)
{
pgd_t *page_dir;
pmd_t *page_middle;
pte_t pte;
- if (!p || !p->mm || ptr >= TASK_SIZE)
+ if (ptr >= TASK_SIZE)
return 0;
- /* Check for NULL pgd .. shouldn't happen! */
- if (!p->mm->pgd) {
- printk("get_phys_addr: pid %d has NULL pgd!\n", p->pid);
- return 0;
- }
-
- page_dir = pgd_offset(p->mm,ptr);
+ page_dir = pgd_offset(mm,ptr);
if (pgd_none(*page_dir))
return 0;
if (pgd_bad(*page_dir)) {
@@ -422,7 +437,9 @@ static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
return pte_page(pte) + (ptr & ~PAGE_MASK);
}
-static int get_array(struct task_struct *p, unsigned long start, unsigned long end, char * buffer)
+#include <linux/bigmem.h>
+
+static int get_array(struct mm_struct *mm, unsigned long start, unsigned long end, char * buffer)
{
unsigned long addr;
int size = 0, result = 0;
@@ -431,49 +448,68 @@ static int get_array(struct task_struct *p, unsigned long start, unsigned long e
if (start >= end)
return result;
for (;;) {
- addr = get_phys_addr(p, start);
+ addr = get_phys_addr(mm, start);
if (!addr)
return result;
+ addr = kmap(addr, KM_READ);
do {
c = *(char *) addr;
if (!c)
result = size;
if (size < PAGE_SIZE)
buffer[size++] = c;
- else
+ else {
+ kunmap(addr, KM_READ);
return result;
+ }
addr++;
start++;
- if (!c && start >= end)
+ if (!c && start >= end) {
+ kunmap(addr, KM_READ);
return result;
+ }
} while (addr & ~PAGE_MASK);
+ kunmap(addr, KM_READ);
}
return result;
}
-static int get_env(int pid, char * buffer)
+static struct mm_struct *get_mm(int pid)
{
struct task_struct *p;
+ struct mm_struct *mm = NULL;
read_lock(&tasklist_lock);
p = find_task_by_pid(pid);
- read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
+ if (p)
+ mm = p->mm;
+ if (mm)
+ atomic_inc(&mm->mm_users);
+ read_unlock(&tasklist_lock);
+ return mm;
+}
- if (!p || !p->mm)
- return 0;
- return get_array(p, p->mm->env_start, p->mm->env_end, buffer);
+
+static int get_env(int pid, char * buffer)
+{
+ struct mm_struct *mm = get_mm(pid);
+ int res = 0;
+ if (mm) {
+ res = get_array(mm, mm->env_start, mm->env_end, buffer);
+ mmput(mm);
+ }
+ return res;
}
static int get_arg(int pid, char * buffer)
{
- struct task_struct *p;
-
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
- if (!p || !p->mm)
- return 0;
- return get_array(p, p->mm->arg_start, p->mm->arg_end, buffer);
+ struct mm_struct *mm = get_mm(pid);
+ int res = 0;
+ if (mm) {
+ res = get_array(mm, mm->arg_start, mm->arg_end, buffer);
+ mmput(mm);
+ }
+ return res;
}
/*
@@ -495,13 +531,13 @@ static unsigned long get_wchan(struct task_struct *p)
int count = 0;
stack_page = (unsigned long)p;
- esp = p->tss.esp;
- if (!stack_page || esp < stack_page || esp >= 8188+stack_page)
+ esp = p->thread.esp;
+ if (!stack_page || esp < stack_page || esp > 8188+stack_page)
return 0;
/* include/asm-i386/system.h:switch_to() pushes ebp last. */
ebp = *(unsigned long *) esp;
do {
- if (ebp < stack_page || ebp >= 8188+stack_page)
+ if (ebp < stack_page || ebp > 8184+stack_page)
return 0;
eip = *(unsigned long *) (ebp+4);
if (eip < first_sched || eip >= last_sched)
@@ -523,9 +559,9 @@ static unsigned long get_wchan(struct task_struct *p)
unsigned long schedule_frame;
unsigned long pc;
- pc = thread_saved_pc(&p->tss);
+ pc = thread_saved_pc(&p->thread);
if (pc >= first_sched && pc < last_sched) {
- schedule_frame = ((unsigned long *)p->tss.ksp)[6];
+ schedule_frame = ((unsigned long *)p->thread.ksp)[6];
return ((unsigned long *)schedule_frame)[12];
}
return pc;
@@ -538,9 +574,9 @@ static unsigned long get_wchan(struct task_struct *p)
unsigned long schedule_frame;
unsigned long pc;
- pc = thread_saved_pc(&p->tss);
+ pc = thread_saved_pc(&p->thread);
if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) {
- schedule_frame = ((unsigned long *)(long)p->tss.reg30)[16];
+ schedule_frame = ((unsigned long *)(long)p->thread.reg30)[16];
return (unsigned long)((unsigned long *)schedule_frame)[11];
}
return pc;
@@ -552,7 +588,7 @@ static unsigned long get_wchan(struct task_struct *p)
int count = 0;
stack_page = (unsigned long)p;
- fp = ((struct switch_stack *)p->tss.ksp)->a6;
+ fp = ((struct switch_stack *)p->thread.ksp)->a6;
do {
if (fp < stack_page+sizeof(struct task_struct) ||
fp >= 8184+stack_page)
@@ -570,7 +606,7 @@ static unsigned long get_wchan(struct task_struct *p)
unsigned long stack_page = (unsigned long) p;
int count = 0;
- sp = p->tss.ksp;
+ sp = p->thread.ksp;
do {
sp = *(unsigned long *)sp;
if (sp < stack_page || sp >= stack_page + 8188)
@@ -609,7 +645,7 @@ static unsigned long get_wchan(struct task_struct *p)
#ifdef __sparc_v9__
bias = STACK_BIAS;
#endif
- fp = p->tss.ksp + bias;
+ fp = p->thread.ksp + bias;
do {
/* Bogus frame pointer? */
if (fp < (task_base + sizeof(struct task_struct)) ||
@@ -638,7 +674,7 @@ static unsigned long get_wchan(struct task_struct *p)
+ (long)&((struct pt_regs *)0)->reg)
# define KSTK_EIP(tsk) \
(*(unsigned long *)(PT_REG(pc) + PAGE_SIZE + (unsigned long)(tsk)))
-# define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
+# define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
#elif defined(__arm__)
# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020])
@@ -646,26 +682,29 @@ static unsigned long get_wchan(struct task_struct *p)
#define KSTK_EIP(tsk) \
({ \
unsigned long eip = 0; \
- if ((tsk)->tss.esp0 > PAGE_SIZE && \
- MAP_NR((tsk)->tss.esp0) < max_mapnr) \
- eip = ((struct pt_regs *) (tsk)->tss.esp0)->pc; \
+ if ((tsk)->thread.esp0 > PAGE_SIZE && \
+ MAP_NR((tsk)->thread.esp0) < max_mapnr) \
+ eip = ((struct pt_regs *) (tsk)->thread.esp0)->pc; \
eip; })
-#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
+#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
#elif defined(__powerpc__)
-#define KSTK_EIP(tsk) ((tsk)->tss.regs->nip)
-#define KSTK_ESP(tsk) ((tsk)->tss.regs->gpr[1])
+#define KSTK_EIP(tsk) ((tsk)->thread.regs->nip)
+#define KSTK_ESP(tsk) ((tsk)->thread.regs->gpr[1])
#elif defined (__sparc_v9__)
-# define KSTK_EIP(tsk) ((tsk)->tss.kregs->tpc)
-# define KSTK_ESP(tsk) ((tsk)->tss.kregs->u_regs[UREG_FP])
+# define KSTK_EIP(tsk) ((tsk)->thread.kregs->tpc)
+# define KSTK_ESP(tsk) ((tsk)->thread.kregs->u_regs[UREG_FP])
#elif defined(__sparc__)
-# define KSTK_EIP(tsk) ((tsk)->tss.kregs->pc)
-# define KSTK_ESP(tsk) ((tsk)->tss.kregs->u_regs[UREG_FP])
+# define KSTK_EIP(tsk) ((tsk)->thread.kregs->pc)
+# define KSTK_ESP(tsk) ((tsk)->thread.kregs->u_regs[UREG_FP])
#elif defined(__mips__)
# define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg \
- sizeof(struct pt_regs))
#define KSTK_TOS(tsk) ((unsigned long)(tsk) + KERNEL_STACK_SIZE - 32)
# define KSTK_EIP(tsk) (*(unsigned long *)(KSTK_TOS(tsk) + PT_REG(cp0_epc)))
# define KSTK_ESP(tsk) (*(unsigned long *)(KSTK_TOS(tsk) + PT_REG(regs[29])))
+#elif defined(__sh__)
+# define KSTK_EIP(tsk) ((tsk)->thread.pc)
+# define KSTK_ESP(tsk) ((tsk)->thread.sp)
#endif
/* Gcc optimizes away "strlen(x)" for constant x */
@@ -747,11 +786,13 @@ static inline char * task_state(struct task_struct *p, char *buffer)
"PPid:\t%d\n"
"Uid:\t%d\t%d\t%d\t%d\n"
"Gid:\t%d\t%d\t%d\t%d\n"
+ "FDSize:\t%d\n"
"Groups:\t",
get_task_state(p),
p->pid, p->p_pptr->pid,
p->uid, p->euid, p->suid, p->fsuid,
- p->gid, p->egid, p->sgid, p->fsgid);
+ p->gid, p->egid, p->sgid, p->fsgid,
+ p->files ? p->files->max_fds : 0);
for (g = 0; g < p->ngroups; g++)
buffer += sprintf(buffer, "%d ", p->groups[g]);
@@ -760,46 +801,44 @@ static inline char * task_state(struct task_struct *p, char *buffer)
return buffer;
}
-static inline char * task_mem(struct task_struct *p, char *buffer)
+static inline char * task_mem(struct mm_struct *mm, char *buffer)
{
- struct mm_struct * mm = p->mm;
-
- if (mm && mm != &init_mm) {
- struct vm_area_struct * vma = mm->mmap;
- unsigned long data = 0, stack = 0;
- unsigned long exec = 0, lib = 0;
-
- for (vma = mm->mmap; vma; vma = vma->vm_next) {
- unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
- if (!vma->vm_file) {
- data += len;
- if (vma->vm_flags & VM_GROWSDOWN)
- stack += len;
- continue;
- }
- if (vma->vm_flags & VM_WRITE)
+ struct vm_area_struct * vma;
+ unsigned long data = 0, stack = 0;
+ unsigned long exec = 0, lib = 0;
+
+ down(&mm->mmap_sem);
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ unsigned long len = (vma->vm_end - vma->vm_start) >> 10;
+ if (!vma->vm_file) {
+ data += len;
+ if (vma->vm_flags & VM_GROWSDOWN)
+ stack += len;
+ continue;
+ }
+ if (vma->vm_flags & VM_WRITE)
+ continue;
+ if (vma->vm_flags & VM_EXEC) {
+ exec += len;
+ if (vma->vm_flags & VM_EXECUTABLE)
continue;
- if (vma->vm_flags & VM_EXEC) {
- exec += len;
- if (vma->vm_flags & VM_EXECUTABLE)
- continue;
- lib += len;
- }
- }
- buffer += sprintf(buffer,
- "VmSize:\t%8lu kB\n"
- "VmLck:\t%8lu kB\n"
- "VmRSS:\t%8lu kB\n"
- "VmData:\t%8lu kB\n"
- "VmStk:\t%8lu kB\n"
- "VmExe:\t%8lu kB\n"
- "VmLib:\t%8lu kB\n",
- mm->total_vm << (PAGE_SHIFT-10),
- mm->locked_vm << (PAGE_SHIFT-10),
- mm->rss << (PAGE_SHIFT-10),
- data - stack, stack,
- exec - lib, lib);
+ lib += len;
+ }
}
+ buffer += sprintf(buffer,
+ "VmSize:\t%8lu kB\n"
+ "VmLck:\t%8lu kB\n"
+ "VmRSS:\t%8lu kB\n"
+ "VmData:\t%8lu kB\n"
+ "VmStk:\t%8lu kB\n"
+ "VmExe:\t%8lu kB\n"
+ "VmLib:\t%8lu kB\n",
+ mm->total_vm << (PAGE_SHIFT-10),
+ mm->locked_vm << (PAGE_SHIFT-10),
+ mm->rss << (PAGE_SHIFT-10),
+ data - stack, stack,
+ exec - lib, lib);
+ up(&mm->mmap_sem);
return buffer;
}
@@ -860,44 +899,61 @@ static int get_status(int pid, char * buffer)
{
char * orig = buffer;
struct task_struct *tsk;
+ struct mm_struct *mm = NULL;
read_lock(&tasklist_lock);
tsk = find_task_by_pid(pid);
+ if (tsk)
+ mm = tsk->mm;
+ if (mm)
+ atomic_inc(&mm->mm_users);
read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!tsk)
return 0;
buffer = task_name(tsk, buffer);
buffer = task_state(tsk, buffer);
- buffer = task_mem(tsk, buffer);
+ if (mm)
+ buffer = task_mem(mm, buffer);
buffer = task_sig(tsk, buffer);
buffer = task_cap(tsk, buffer);
+ if (mm)
+ mmput(mm);
return buffer - orig;
}
static int get_stat(int pid, char * buffer)
{
struct task_struct *tsk;
+ struct mm_struct *mm = NULL;
unsigned long vsize, eip, esp, wchan;
long priority, nice;
int tty_pgrp;
sigset_t sigign, sigcatch;
char state;
+ int res;
read_lock(&tasklist_lock);
tsk = find_task_by_pid(pid);
+ if (tsk)
+ mm = tsk->mm;
+ if (mm)
+ atomic_inc(&mm->mm_users);
read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
if (!tsk)
return 0;
state = *get_task_state(tsk);
vsize = eip = esp = 0;
- if (tsk->mm && tsk->mm != &init_mm) {
- struct vm_area_struct *vma = tsk->mm->mmap;
+ if (mm) {
+ struct vm_area_struct *vma;
+ down(&mm->mmap_sem);
+ vma = mm->mmap;
while (vma) {
vsize += vma->vm_end - vma->vm_start;
vma = vma->vm_next;
}
eip = KSTK_EIP(tsk);
esp = KSTK_ESP(tsk);
+ up(&mm->mmap_sem);
}
wchan = get_wchan(tsk);
@@ -916,7 +972,7 @@ static int get_stat(int pid, char * buffer)
nice = tsk->priority;
nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY;
- return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
+ res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
pid,
@@ -942,11 +998,11 @@ static int get_stat(int pid, char * buffer)
tsk->it_real_value,
tsk->start_time,
vsize,
- tsk->mm ? tsk->mm->rss : 0, /* you might want to shift this left 3 */
+ mm ? mm->rss : 0, /* you might want to shift this left 3 */
tsk->rlim ? tsk->rlim[RLIMIT_RSS].rlim_cur : 0,
- tsk->mm ? tsk->mm->start_code : 0,
- tsk->mm ? tsk->mm->end_code : 0,
- tsk->mm ? tsk->mm->start_stack : 0,
+ mm ? mm->start_code : 0,
+ mm ? mm->end_code : 0,
+ mm ? mm->start_stack : 0,
esp,
eip,
/* The signal information here is obsolete.
@@ -962,6 +1018,9 @@ static int get_stat(int pid, char * buffer)
tsk->cnswap,
tsk->exit_signal,
tsk->processor);
+ if (mm)
+ mmput(mm);
+ return res;
}
static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
@@ -1039,19 +1098,15 @@ static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long en
static int get_statm(int pid, char * buffer)
{
- struct task_struct *tsk;
+ struct mm_struct *mm = get_mm(pid);
int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
- read_lock(&tasklist_lock);
- tsk = find_task_by_pid(pid);
- read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
- if (!tsk)
- return 0;
- if (tsk->mm && tsk->mm != &init_mm) {
- struct vm_area_struct * vma = tsk->mm->mmap;
-
+ if (mm) {
+ struct vm_area_struct * vma;
+ down(&mm->mmap_sem);
+ vma = mm->mmap;
while (vma) {
- pgd_t *pgd = pgd_offset(tsk->mm, vma->vm_start);
+ pgd_t *pgd = pgd_offset(mm, vma->vm_start);
int pages = 0, shared = 0, dirty = 0, total = 0;
statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total);
@@ -1069,6 +1124,8 @@ static int get_statm(int pid, char * buffer)
drs += pages;
vma = vma->vm_next;
}
+ up(&mm->mmap_sem);
+ mmput(mm);
}
return sprintf(buffer,"%d %d %d %d %d %d %d\n",
size, resident, share, trs, lrs, drs, dt);
@@ -1133,11 +1190,11 @@ static ssize_t read_maps (int pid, struct file * file, char * buf,
if (!p)
goto freepage_out;
- if (!p->mm || p->mm == &init_mm || count == 0)
+ if (!p->mm || count == 0)
goto getlen_out;
/* Check whether the mmaps could change if we sleep */
- volatile_task = (p != current || atomic_read(&p->mm->count) > 1);
+ volatile_task = (p != current || atomic_read(&p->mm->mm_users) > 1);
/* decode f_pos */
lineno = *ppos >> MAPS_LINE_SHIFT;
@@ -1296,7 +1353,7 @@ static long get_root_array(char * page, int type, char **start,
case PROC_MEMINFO:
return get_meminfo(page);
-#ifdef CONFIG_PCI_OLD_PROC
+#ifdef CONFIG_PCI
case PROC_PCI:
return get_pci_list(page);
#endif
@@ -1404,8 +1461,6 @@ static int process_unauthorized(int type, int pid)
ok = p->dumpable;
if(!cap_issubset(p->cap_permitted, current->cap_permitted))
ok=0;
- if(!p->mm) /* Scooby scooby doo where are you ? */
- p=NULL;
}
read_unlock(&tasklist_lock);
@@ -1413,8 +1468,7 @@ static int process_unauthorized(int type, int pid)
if (!p)
return 1;
- switch(type)
- {
+ switch(type) {
case PROC_PID_STATUS:
case PROC_PID_STATM:
case PROC_PID_STAT:
@@ -1481,8 +1535,7 @@ static ssize_t array_read(struct file * file, char * buf,
start = NULL;
dp = (struct proc_dir_entry *) inode->u.generic_ip;
- if (pid && process_unauthorized(type, pid))
- {
+ if (pid && process_unauthorized(type, pid)) {
free_page(page);
return -EIO;
}
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 118e94956..f0a0febf8 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -178,7 +178,7 @@ static struct proc_dir_entry proc_pid_cpu = {
};
#endif
-__initfunc(void proc_base_init(void))
+void __init proc_base_init(void)
{
#if CONFIG_AP1000
proc_register(&proc_pid, &proc_pid_ringbuf);
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 195ca41b8..1862f6f5f 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -90,6 +90,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry)
fd = 0;
len = dentry->d_name.len;
name = dentry->d_name.name;
+ if (len > 1 && *name == '0') goto out;
while (len-- > 0) {
c = *name - '0';
name++;
@@ -133,7 +134,7 @@ out:
static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
{
struct inode *inode = filp->f_dentry->d_inode;
- struct task_struct * p, **tarrayp;
+ struct task_struct *p, *tmp;
unsigned int fd, pid, ino;
int retval;
char buf[NUMBUF];
@@ -157,7 +158,6 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
p = find_task_by_pid(pid);
if (!p)
goto out_unlock;
- tarrayp = p->tarray_ptr;
for (fd -= 2 ; p->files && fd < p->files->max_fds; fd++, filp->f_pos++)
{
@@ -182,8 +182,13 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
goto out;
read_lock(&tasklist_lock);
- /* filldir() might have slept, so we must re-validate "p" */
- if (p != *tarrayp || p->pid != pid)
+ /*
+ * filldir() might have slept, so we must
+ * re-validate "p". This is fast enough due
+ * to the pidhash
+ */
+ tmp = find_task_by_pid(pid);
+ if (p != tmp)
break;
}
out_unlock:
diff --git a/fs/proc/link.c b/fs/proc/link.c
index 6f5c63ec3..69d435600 100644
--- a/fs/proc/link.c
+++ b/fs/proc/link.c
@@ -82,60 +82,70 @@ static struct dentry * proc_follow_link(struct dentry *dentry,
ino &= 0x0000ffff;
result = ERR_PTR(-ENOENT);
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (!p)
- goto out_unlock;
switch (ino) {
case PROC_PID_CWD:
- if (!p->fs || !p->fs->pwd)
- goto out_unlock;
- result = p->fs->pwd;
- goto out_dget;
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+ if (p && p->fs && p->fs->pwd)
+ result = dget(p->fs->pwd);
+ read_unlock(&tasklist_lock);
+ break;
case PROC_PID_ROOT:
- if (!p->fs || !p->fs->root)
- goto out_unlock;
- result = p->fs->root;
- goto out_dget;
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+ if (p && p->fs && p->fs->root)
+ result = dget(p->fs->root);
+ read_unlock(&tasklist_lock);
+ break;
case PROC_PID_EXE: {
+ struct mm_struct *mm = NULL;
struct vm_area_struct * vma;
- if (!p->mm)
- goto out_unlock;
- vma = p->mm->mmap;
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+ if (p)
+ mm = p->mm;
+ if (mm)
+ atomic_inc(&mm->mm_users);
+ read_unlock(&tasklist_lock);
+ if (!mm)
+ break;
+ down(&mm->mmap_sem);
+ vma = mm->mmap;
while (vma) {
if ((vma->vm_flags & VM_EXECUTABLE) &&
vma->vm_file) {
- result = vma->vm_file->f_dentry;
- goto out_dget;
+ result = dget(vma->vm_file->f_dentry);
+ break;
}
vma = vma->vm_next;
}
- goto out_unlock;
+ up(&mm->mmap_sem);
+ mmput(mm);
+ break;
}
default:
if (ino & PROC_PID_FD_DIR) {
struct file * file;
+ struct files_struct *files = NULL;
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+ if (p)
+ files = p->files;
+ read_unlock(&tasklist_lock);
+ if (!files)
+ break;
ino &= 0x7fff;
- if (!p->files) /* shouldn't happen here */
- goto out_unlock;
- read_lock(&p->files->file_lock);
- file = fcheck_task(p, ino);
- if (!file || !file->f_dentry)
- goto out_unlock;
- result = file->f_dentry;
+ read_lock(&files->file_lock);
+ /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
+ if (ino < files->max_fds &&
+ (file = files->fd[ino]) && file->f_dentry)
+ result = dget(file->f_dentry);
read_unlock(&p->files->file_lock);
- goto out_dget;
}
}
-out_dget:
- result = dget(result);
-
-out_unlock:
- read_unlock(&tasklist_lock);
-
out:
return result;
}
diff --git a/fs/proc/mem.c b/fs/proc/mem.c
index 4d599c77b..f9fcb0970 100644
--- a/fs/proc/mem.c
+++ b/fs/proc/mem.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
+#include <linux/bigmem.h>
#include <asm/page.h>
#include <asm/uaccess.h>
@@ -120,7 +121,9 @@ static ssize_t mem_read(struct file * file, char * buf,
i = PAGE_SIZE-(addr & ~PAGE_MASK);
if (i > scount)
i = scount;
+ page = (char *) kmap((unsigned long) page, KM_READ);
copy_to_user(tmp, page, i);
+ kunmap((unsigned long) page, KM_READ);
addr += i;
tmp += i;
scount -= i;
@@ -177,7 +180,9 @@ static ssize_t mem_write(struct file * file, char * buf,
i = PAGE_SIZE-(addr & ~PAGE_MASK);
if (i > count)
i = count;
+ page = (unsigned long) kmap((unsigned long) page, KM_WRITE);
copy_from_user(page, tmp, i);
+ kunmap((unsigned long) page, KM_WRITE);
addr += i;
tmp += i;
count -= i;
diff --git a/fs/proc/openpromfs.c b/fs/proc/openpromfs.c
index 72bb194cf..c9553ea24 100644
--- a/fs/proc/openpromfs.c
+++ b/fs/proc/openpromfs.c
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.33 1999/04/28 11:57:33 davem Exp $
+/* $Id: openpromfs.c,v 1.36 1999/08/31 07:01:03 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
* Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -990,7 +990,7 @@ static int openpromfs_unlink (struct inode *dir, struct dentry *dentry)
/* {{{ init section */
#ifndef MODULE
-__initfunc(static int check_space (u16 n))
+static int __init check_space (u16 n)
#else
static int check_space (u16 n)
#endif
@@ -1014,7 +1014,7 @@ static int check_space (u16 n)
}
#ifndef MODULE
-__initfunc(static u16 get_nodes (u16 parent, u32 node))
+static u16 __init get_nodes (u16 parent, u32 node)
#else
static u16 get_nodes (u16 parent, u32 node)
#endif
@@ -1132,7 +1132,7 @@ void openpromfs_use (struct inode *inode, int inc)
#ifndef MODULE
#define RET(x)
-__initfunc(void openpromfs_init (void))
+void __init openpromfs_init (void)
#else
EXPORT_NO_SYMBOLS;
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c
index 5ba245615..4b4ca41b8 100644
--- a/fs/proc/proc_tty.c
+++ b/fs/proc/proc_tty.c
@@ -170,7 +170,7 @@ void proc_tty_unregister_driver(struct tty_driver *driver)
/*
* Called by proc_root_init() to initialize the /proc/tty subtree
*/
-__initfunc(void proc_tty_init(void))
+void __init proc_tty_init(void)
{
struct proc_dir_entry *ent;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index df3c0b049..65ef929e7 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -641,6 +641,14 @@ struct proc_dir_entry proc_root_fs = {
NULL,
NULL, NULL
};
+struct proc_dir_entry proc_root_driver = {
+ PROC_DRIVER, 6, "driver",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+ 0, &proc_dir_inode_operations,
+ NULL, NULL,
+ NULL,
+ NULL, NULL
+};
static struct proc_dir_entry proc_root_dma = {
PROC_DMA, 3, "dma",
S_IFREG | S_IRUGO, 1, 0, 0,
@@ -651,8 +659,8 @@ static struct proc_dir_entry proc_root_ioports = {
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_array_inode_operations
};
-static struct proc_dir_entry proc_root_memory = {
- PROC_MEMORY, 6, "memory",
+static struct proc_dir_entry proc_root_iomem = {
+ PROC_MEMORY, 5, "iomem",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_array_inode_operations
};
@@ -711,7 +719,7 @@ static struct proc_dir_entry proc_root_ppc_htab = {
};
#endif
-__initfunc(void proc_root_init(void))
+void __init proc_root_init(void)
{
proc_base_init();
proc_register(&proc_root, &proc_root_loadavg);
@@ -745,13 +753,14 @@ __initfunc(void proc_root_init(void))
#endif
proc_register(&proc_root, &proc_root_stat);
proc_register(&proc_root, &proc_root_devices);
+ proc_register(&proc_root, &proc_root_driver);
proc_register(&proc_root, &proc_root_partitions);
proc_register(&proc_root, &proc_root_interrupts);
proc_register(&proc_root, &proc_root_filesystems);
proc_register(&proc_root, &proc_root_fs);
proc_register(&proc_root, &proc_root_dma);
proc_register(&proc_root, &proc_root_ioports);
- proc_register(&proc_root, &proc_root_memory);
+ proc_register(&proc_root, &proc_root_iomem);
proc_register(&proc_root, &proc_root_cmdline);
#ifdef CONFIG_RTC
proc_register(&proc_root, &proc_root_rtc);
@@ -859,14 +868,29 @@ static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentr
int len;
if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */
- dir->i_nlink = proc_root.nlink;
-
- read_lock(&tasklist_lock);
- for_each_task(p) {
- if (p->pid)
- dir->i_nlink++;
+ extern unsigned long total_forks;
+ static int last_timestamp = 0;
+
+ /*
+ * this one can be a serious 'ps' performance problem if
+ * there are many threads running - thus we do 'lazy'
+ * link-recalculation - we change it only if the number
+ * of threads has increased.
+ */
+ if (total_forks != last_timestamp) {
+ int nlink = proc_root.nlink;
+
+ read_lock(&tasklist_lock);
+ last_timestamp = total_forks;
+ for_each_task(p)
+ nlink++;
+ read_unlock(&tasklist_lock);
+ /*
+ * subtract the # of idle threads which
+ * do not show up in /proc:
+ */
+ dir->i_nlink = nlink - smp_num_cpus;
}
- read_unlock(&tasklist_lock);
}
if (!proc_lookup(dir, dentry))
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 0f5262301..3acd5e028 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -27,7 +27,6 @@
#define QNX4_VERSION 4
#define QNX4_BMNAME ".bitmap"
-#define CHECK_BOOT_SIGNATURE 0
static struct super_operations qnx4_sops;
@@ -257,9 +256,6 @@ static const char *qnx4_checkroot(struct super_block *s)
int i, j;
int found = 0;
- if (s == NULL) {
- return "no qnx4 filesystem (null superblock).";
- }
if (*(s->u.qnx4_sb.sb->RootDir.di_fname) != '/') {
return "no qnx4 filesystem (no root dir).";
} else {
@@ -282,6 +278,8 @@ static const char *qnx4_checkroot(struct super_block *s)
}
}
}
+ /* WAIT! s->u.qnx4_sb.BitMap points into bh->b_data
+ and now we release bh?? */
brelse(bh);
if (found != 0) {
break;
@@ -299,9 +297,8 @@ static struct super_block *qnx4_read_super(struct super_block *s,
{
struct buffer_head *bh;
kdev_t dev = s->s_dev;
-#if CHECK_BOOT_SIGNATURE
+ struct inode *root;
char *tmpc;
-#endif
const char *errmsg;
MOD_INC_USE_COUNT;
@@ -311,7 +308,9 @@ static struct super_block *qnx4_read_super(struct super_block *s,
s->s_blocksize_bits = 9;
s->s_dev = dev;
-#if CHECK_BOOT_SIGNATURE
+ /* Check the boot signature. Since the qnx4 code is
+ dangerous, we should leave as quickly as possible
+ if we don't belong here... */
bh = bread(dev, 0, QNX4_BLOCK_SIZE);
if (!bh) {
printk("qnx4: unable to read the boot sector\n");
@@ -320,11 +319,12 @@ static struct super_block *qnx4_read_super(struct super_block *s,
tmpc = (char *) bh->b_data;
if (tmpc[4] != 'Q' || tmpc[5] != 'N' || tmpc[6] != 'X' ||
tmpc[7] != '4' || tmpc[8] != 'F' || tmpc[9] != 'S') {
- printk("qnx4: wrong fsid in boot sector.\n");
+ if (!silent)
+ printk("qnx4: wrong fsid in boot sector.\n");
goto out;
}
brelse(bh);
-#endif
+
bh = bread(dev, 1, QNX4_BLOCK_SIZE);
if (!bh) {
printk("qnx4: unable to read the superblock\n");
@@ -337,23 +337,35 @@ static struct super_block *qnx4_read_super(struct super_block *s,
#endif
s->u.qnx4_sb.sb_buf = bh;
s->u.qnx4_sb.sb = (struct qnx4_super_block *) bh->b_data;
- s->s_root =
- d_alloc_root(iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK));
- if (s->s_root == NULL) {
- printk("qnx4: get inode failed\n");
- goto out;
- }
+
+
+ /* check before allocating dentries, inodes, .. */
errmsg = qnx4_checkroot(s);
if (errmsg != NULL) {
- printk("qnx4: %s\n", errmsg);
+ if (!silent)
+ printk("qnx4: %s\n", errmsg);
goto out;
}
+
+ /* does root not have inode number QNX4_ROOT_INO ?? */
+ root = iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK);
+ if (!root) {
+ printk("qnx4: get inode failed\n");
+ goto out;
+ }
+
+ s->s_root = d_alloc_root(root);
+ if (s->s_root == NULL)
+ goto outi;
+
brelse(bh);
unlock_super(s);
s->s_dirt = 1;
return s;
+ outi:
+ iput(root);
out:
brelse(bh);
outnobh:
@@ -430,7 +442,7 @@ static struct file_system_type qnx4_fs_type =
NULL
};
-__initfunc(int init_qnx4_fs(void))
+int __init init_qnx4_fs(void)
{
printk("QNX4 filesystem v0.2 registered.\n");
return register_filesystem(&qnx4_fs_type);
diff --git a/fs/read_write.c b/fs/read_write.c
index cf207fed0..81f6d1141 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -13,7 +13,7 @@
#include <asm/uaccess.h>
-static loff_t default_llseek(struct file *file, loff_t offset, int origin)
+loff_t default_llseek(struct file *file, loff_t offset, int origin)
{
long long retval;
@@ -73,9 +73,9 @@ bad:
}
#if !defined(__alpha__)
-asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
- unsigned long offset_low, loff_t * result,
- unsigned int origin)
+asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
+ unsigned long offset_low, loff_t * result,
+ unsigned int origin)
{
int retval;
struct file * file;
diff --git a/fs/readdir.c b/fs/readdir.c
index 305b1cc74..31bc56cc2 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -142,7 +142,7 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in
return 0;
}
-asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count)
+asmlinkage long sys_getdents(unsigned int fd, void * dirent, unsigned int count)
{
struct file * file;
struct dentry * dentry;
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index e16802e97..a30f382a6 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -405,7 +405,7 @@ romfs_readpage(struct file * file, struct page * page)
buf = page_address(page);
/* hack? */
- page->owner = (int)current;
+ page->owner = current;
offset = page->offset;
if (offset < inode->i_size) {
@@ -692,7 +692,7 @@ static struct file_system_type romfs_fs_type = {
NULL
};
-__initfunc(int init_romfs_fs(void))
+int __init init_romfs_fs(void)
{
return register_filesystem(&romfs_fs_type);
}
diff --git a/fs/select.c b/fs/select.c
index 3f278187e..674cfdaa2 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -106,7 +106,7 @@ static int max_select_fd(unsigned long n, fd_set_bits *fds)
/* handle last in-complete long-word first */
set = ~(~0UL << (n & (__NFDBITS-1)));
n /= __NFDBITS;
- open_fds = current->files->open_fds.fds_bits+n;
+ open_fds = current->files->open_fds->fds_bits+n;
max = 0;
if (set) {
set &= BITS(fds, n);
@@ -174,7 +174,7 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
n = retval;
retval = 0;
for (;;) {
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
for (i = 0 ; i < n; i++) {
unsigned long bit = BIT(i);
unsigned long mask;
@@ -237,7 +237,7 @@ out:
#define MAX_SELECT_SECONDS \
((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
-asmlinkage int
+asmlinkage long
sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
{
fd_set_bits fds;
@@ -268,8 +268,8 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
if (n < 0)
goto out_nofds;
- if (n > KFDS_NR)
- n = KFDS_NR;
+ if (n > current->files->max_fdset)
+ n = current->files->max_fdset;
/*
* We need 6 bitmaps (in/out/ex for both incoming and outgoing),
@@ -337,7 +337,7 @@ static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait,
unsigned int j;
struct pollfd * fdpnt;
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
for (fdpnt = fds, j = 0; j < nfds; j++, fdpnt++) {
int fd;
unsigned int mask;
@@ -371,7 +371,7 @@ static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait,
return count;
}
-asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
+asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
{
int i, fdcount, err, size;
struct pollfd * fds, *fds1;
@@ -380,7 +380,7 @@ asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
lock_kernel();
/* Do a sanity check on nfds ... */
err = -EINVAL;
- if (nfds > NR_OPEN)
+ if (nfds > current->files->max_fds)
goto out;
if (timeout) {
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index cf3539823..419adf970 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -575,7 +575,7 @@ static struct file_system_type smb_fs_type = {
NULL
};
-__initfunc(int init_smb_fs(void))
+int __init init_smb_fs(void)
{
return register_filesystem(&smb_fs_type);
}
diff --git a/fs/stat.c b/fs/stat.c
index 146790d67..709477439 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -119,7 +119,7 @@ static int cp_new_stat(struct inode * inode, struct stat * statbuf)
* For backward compatibility? Maybe this should be moved
* into arch/i386 instead?
*/
-asmlinkage int sys_stat(char * filename, struct __old_kernel_stat * statbuf)
+asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf)
{
struct dentry * dentry;
int error;
@@ -140,7 +140,7 @@ asmlinkage int sys_stat(char * filename, struct __old_kernel_stat * statbuf)
}
#endif
-asmlinkage int sys_newstat(char * filename, struct stat * statbuf)
+asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
{
struct dentry * dentry;
int error;
@@ -166,7 +166,7 @@ asmlinkage int sys_newstat(char * filename, struct stat * statbuf)
* For backward compatibility? Maybe this should be moved
* into arch/i386 instead?
*/
-asmlinkage int sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
+asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
{
struct dentry * dentry;
int error;
@@ -188,7 +188,7 @@ asmlinkage int sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
#endif
-asmlinkage int sys_newlstat(char * filename, struct stat * statbuf)
+asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
{
struct dentry * dentry;
int error;
@@ -214,7 +214,7 @@ asmlinkage int sys_newlstat(char * filename, struct stat * statbuf)
* For backward compatibility? Maybe this should be moved
* into arch/i386 instead?
*/
-asmlinkage int sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf)
+asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf)
{
struct file * f;
int err = -EBADF;
@@ -235,7 +235,7 @@ asmlinkage int sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf)
#endif
-asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf)
+asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf)
{
struct file * f;
int err = -EBADF;
@@ -254,7 +254,7 @@ asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf)
return err;
}
-asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz)
+asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz)
{
struct dentry * dentry;
int error;
diff --git a/fs/super.c b/fs/super.c
index f70815094..efd0a5972 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -256,7 +256,7 @@ static int fs_maxindex(void)
/*
* Whee.. Weird sysv syscall.
*/
-asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
+asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
{
int retval = -EINVAL;
@@ -417,7 +417,7 @@ void __wait_on_super(struct super_block * sb)
add_wait_queue(&sb->s_wait, &wait);
repeat:
- current->state = TASK_UNINTERRUPTIBLE;
+ set_current_state(TASK_UNINTERRUPTIBLE);
if (sb->s_lock) {
schedule();
goto repeat;
@@ -474,7 +474,7 @@ restart:
return NULL;
}
-asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf)
+asmlinkage long sys_ustat(dev_t dev, struct ustat * ubuf)
{
struct super_block *s;
struct ustat tmp;
@@ -768,7 +768,7 @@ out:
* unixes. Our API is identical to OSF/1 to avoid making a mess of AMD
*/
-asmlinkage int sys_umount(char * name, int flags)
+asmlinkage long sys_umount(char * name, int flags)
{
struct dentry * dentry;
int retval;
@@ -808,7 +808,7 @@ asmlinkage int sys_umount(char * name, int flags)
* The 2.0 compatible umount. No flags.
*/
-asmlinkage int sys_oldumount(char * name)
+asmlinkage long sys_oldumount(char * name)
{
return sys_umount(name,0);
}
@@ -1018,8 +1018,8 @@ static int copy_mount_options (const void * data, unsigned long *where)
* aren't used, as the syscall assumes we are talking to an older
* version that didn't understand them.
*/
-asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
- unsigned long new_flags, void * data)
+asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
+ unsigned long new_flags, void * data)
{
struct file_system_type * fstype;
struct dentry * dentry = NULL;
@@ -1166,6 +1166,7 @@ void __init mount_root(void)
if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
#ifdef CONFIG_BLK_DEV_RAM
extern int rd_doload;
+ extern void rd_load_secondary(void);
#endif
floppy_eject();
#ifndef CONFIG_BLK_DEV_RAM
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index ff10e778d..4e70122c3 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -1174,7 +1174,7 @@ static struct file_system_type sysv_fs_type[3] = {
{"coherent", FS_REQUIRES_DEV, sysv_read_super, NULL}
};
-__initfunc(int init_sysv_fs(void))
+int __init init_sysv_fs(void)
{
int i;
int ouch;
diff --git a/fs/udf/.cvsignore b/fs/udf/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/fs/udf/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/fs/udf/Makefile b/fs/udf/Makefile
new file mode 100644
index 000000000..b1fcbed1f
--- /dev/null
+++ b/fs/udf/Makefile
@@ -0,0 +1,16 @@
+#
+# Makefile for the linux udf-filesystem routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .o file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile..
+
+O_TARGET := udf.o
+O_OBJS := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \
+ partition.o super.o truncate.o symlink.o fsync.o \
+ crc.o directory.o misc.o udftime.o unicode.o
+M_OBJS := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
new file mode 100644
index 000000000..3bcda123c
--- /dev/null
+++ b/fs/udf/balloc.c
@@ -0,0 +1,441 @@
+/*
+ * balloc.c
+ *
+ * PURPOSE
+ * Block allocation handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ *
+ * (C) 1999 Ben Fennema
+ * (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ * 02/24/99 blf Created.
+ *
+ */
+
+#include "udfdecl.h"
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/udf_fs.h>
+
+#include <asm/bitops.h>
+
+#include "udf_i.h"
+#include "udf_sb.h"
+
+static int read_block_bitmap(struct super_block * sb, unsigned int block,
+ unsigned long bitmap_nr)
+{
+ struct buffer_head *bh = NULL;
+ int retval = 0;
+ lb_addr loc;
+
+ loc.logicalBlockNum = UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace_bitmap;
+ loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
+
+ bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block), sb->s_blocksize);
+ if (!bh)
+ {
+ retval = -EIO;
+ }
+ UDF_SB_BLOCK_BITMAP_NUMBER(sb, bitmap_nr) = block;
+ UDF_SB_BLOCK_BITMAP(sb, bitmap_nr) = bh;
+ return retval;
+}
+
+static int load__block_bitmap(struct super_block * sb, unsigned int block_group)
+{
+ int i, j, retval = 0;
+ unsigned long block_bitmap_number;
+ struct buffer_head * block_bitmap = NULL;
+ int nr_groups = (UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb)) +
+ (sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
+
+ if (block_group >= nr_groups)
+ {
+ udf_debug("block_group (%d) > nr_groups (%d)\n", block_group, nr_groups);
+ }
+
+ if (nr_groups <= UDF_MAX_BLOCK_LOADED)
+ {
+ if (UDF_SB_BLOCK_BITMAP(sb, block_group))
+ {
+ if (UDF_SB_BLOCK_BITMAP_NUMBER(sb, block_group) == block_group)
+ return block_group;
+ }
+ retval = read_block_bitmap(sb, block_group, block_group);
+ if (retval < 0)
+ return retval;
+ return block_group;
+ }
+
+ for (i=0; i<UDF_SB_LOADED_BLOCK_BITMAPS(sb) &&
+ UDF_SB_BLOCK_BITMAP_NUMBER(sb, i) != block_group; i++)
+ {
+ ;
+ }
+ if (i < UDF_SB_LOADED_BLOCK_BITMAPS(sb) &&
+ UDF_SB_BLOCK_BITMAP_NUMBER(sb, i) == block_group)
+ {
+ block_bitmap_number = UDF_SB_BLOCK_BITMAP_NUMBER(sb, i);
+ block_bitmap = UDF_SB_BLOCK_BITMAP(sb, i);
+ for (j=i; j>0; j--)
+ {
+ UDF_SB_BLOCK_BITMAP_NUMBER(sb, j) = UDF_SB_BLOCK_BITMAP_NUMBER(sb, j-1);
+ UDF_SB_BLOCK_BITMAP(sb, j) = UDF_SB_BLOCK_BITMAP(sb, j-1);
+ }
+ UDF_SB_BLOCK_BITMAP_NUMBER(sb, 0) = block_bitmap_number;
+ UDF_SB_BLOCK_BITMAP(sb, 0) = block_bitmap;
+
+ if (!block_bitmap)
+ retval = read_block_bitmap(sb, block_group, 0);
+ }
+ else
+ {
+ if (UDF_SB_LOADED_BLOCK_BITMAPS(sb) < UDF_MAX_BLOCK_LOADED)
+ UDF_SB_LOADED_BLOCK_BITMAPS(sb) ++;
+ else
+ brelse(UDF_SB_BLOCK_BITMAP(sb, UDF_MAX_BLOCK_LOADED-1));
+ for (j=UDF_SB_LOADED_BLOCK_BITMAPS(sb)-1; j>0; j--)
+ {
+ UDF_SB_BLOCK_BITMAP_NUMBER(sb, j) = UDF_SB_BLOCK_BITMAP_NUMBER(sb, j-1);
+ UDF_SB_BLOCK_BITMAP(sb, j) = UDF_SB_BLOCK_BITMAP(sb, j-1);
+ }
+ retval = read_block_bitmap(sb, block_group, 0);
+ }
+ return retval;
+}
+
+static inline int load_block_bitmap(struct super_block *sb,
+ unsigned int block_group)
+{
+ int slot;
+ int nr_groups = (UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb)) +
+ (sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
+
+ if (UDF_SB_LOADED_BLOCK_BITMAPS(sb) > 0 &&
+ UDF_SB_BLOCK_BITMAP_NUMBER(sb, 0) == block_group &&
+ UDF_SB_BLOCK_BITMAP(sb, block_group))
+ {
+ return 0;
+ }
+ else if (nr_groups <= UDF_MAX_BLOCK_LOADED &&
+ UDF_SB_BLOCK_BITMAP_NUMBER(sb, block_group) == block_group &&
+ UDF_SB_BLOCK_BITMAP(sb, block_group))
+ {
+ slot = block_group;
+ }
+ else
+ {
+ slot = load__block_bitmap(sb, block_group);
+ }
+
+ if (slot < 0)
+ return slot;
+
+ if (!UDF_SB_BLOCK_BITMAP(sb, slot))
+ return -EIO;
+
+ return slot;
+}
+
+void udf_free_blocks(const struct inode * inode, lb_addr bloc, Uint32 offset,
+ Uint32 count)
+{
+ struct buffer_head * bh = NULL;
+ unsigned long block;
+ unsigned long block_group;
+ unsigned long bit;
+ unsigned long i;
+ int bitmap_nr;
+ unsigned long overflow;
+ struct super_block * sb;
+
+ sb = inode->i_sb;
+ if (!sb)
+ {
+ udf_debug("nonexistent device");
+ return;
+ }
+
+ if (UDF_SB_PARTMAPS(sb)[bloc.partitionReferenceNum].s_uspace_bitmap == 0xFFFFFFFF)
+ return;
+
+ lock_super(sb);
+ if (bloc.logicalBlockNum < 0 ||
+ (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
+ {
+ udf_debug("%d < %d || %d + %d > %d\n",
+ bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
+ UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
+ goto error_return;
+ }
+
+ block = bloc.logicalBlockNum + offset + (sizeof(struct SpaceBitmapDesc) << 3);
+
+do_more:
+ overflow = 0;
+ block_group = block >> (sb->s_blocksize_bits + 3);
+ bit = block % (sb->s_blocksize << 3);
+
+ /*
+ * Check to see if we are freeing blocks across a group boundary.
+ */
+ if (bit + count > (sb->s_blocksize << 3))
+ {
+ overflow = bit + count - (sb->s_blocksize << 3);
+ count -= overflow;
+ }
+ bitmap_nr = load_block_bitmap(sb, block_group);
+ if (bitmap_nr < 0)
+ goto error_return;
+
+ bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
+ for (i=0; i < count; i++)
+ {
+ if (udf_set_bit(bit + i, bh->b_data))
+ {
+ udf_debug("bit %ld already set\n", bit + i);
+ udf_debug("byte=%2x\n", ((char *)bh->b_data)[(bit + i) >> 3]);
+ }
+ else if (UDF_SB_LVIDBH(sb))
+ {
+ UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
+ cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)])+1);
+ }
+ }
+ mark_buffer_dirty(bh, 1);
+ if (overflow)
+ {
+ block += count;
+ count = overflow;
+ goto do_more;
+ }
+error_return:
+ sb->s_dirt = 1;
+ if (UDF_SB_LVIDBH(sb))
+ mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+ unlock_super(sb);
+ return;
+}
+
+int udf_alloc_blocks(const struct inode * inode, Uint16 partition,
+ Uint32 first_block, Uint32 block_count)
+{
+ int alloc_count = 0;
+ int bit, block, block_group, group_start;
+ int nr_groups, bitmap_nr;
+ struct buffer_head *bh;
+ struct super_block *sb;
+
+ sb = inode->i_sb;
+ if (!sb)
+ {
+ udf_debug("nonexistent device\n");
+ return 0;
+ }
+ lock_super(sb);
+
+ if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition))
+ goto out;
+
+repeat:
+ nr_groups = (UDF_SB_PARTLEN(sb, partition) +
+ (sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
+ block = first_block + (sizeof(struct SpaceBitmapDesc) << 3);
+ block_group = block >> (sb->s_blocksize_bits + 3);
+ group_start = block_group ? 0 : sizeof(struct SpaceBitmapDesc);
+
+ bitmap_nr = load_block_bitmap(sb, block_group);
+ if (bitmap_nr < 0)
+ goto out;
+ bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
+
+ bit = block % (sb->s_blocksize << 3);
+
+ while (bit < (sb->s_blocksize << 3) && block_count > 0)
+ {
+ if (!udf_test_bit(bit, bh->b_data))
+ goto out;
+ if (!udf_clear_bit(bit, bh->b_data))
+ {
+ udf_debug("bit already cleared for block %d\n", bit);
+ goto out;
+ }
+ block_count --;
+ alloc_count ++;
+ bit ++;
+ block ++;
+
+ }
+ mark_buffer_dirty(bh, 1);
+ if (block_count > 0)
+ goto repeat;
+out:
+ if (UDF_SB_LVIDBH(sb))
+ {
+ UDF_SB_LVID(sb)->freeSpaceTable[partition] =
+ cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count);
+ mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+ }
+ sb->s_dirt = 1;
+ unlock_super(sb);
+ return alloc_count;
+}
+
+int udf_new_block(const struct inode * inode, Uint16 partition, Uint32 goal, int *err)
+{
+ int tmp, newbit, bit=0, block, block_group, group_start;
+ int end_goal, nr_groups, bitmap_nr, i;
+ struct buffer_head *bh = NULL;
+ struct super_block *sb;
+ char *ptr;
+ int newblock = 0;
+
+ *err = -ENOSPC;
+ sb = inode->i_sb;
+ if (!sb)
+ {
+ udf_debug("nonexistent device\n");
+ return newblock;
+ }
+ lock_super(sb);
+
+repeat:
+ if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition))
+ goal = 0;
+
+ nr_groups = (UDF_SB_PARTLEN(sb, partition) +
+ (sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
+ block = goal + (sizeof(struct SpaceBitmapDesc) << 3);
+ block_group = block >> (sb->s_blocksize_bits + 3);
+ group_start = block_group ? 0 : sizeof(struct SpaceBitmapDesc);
+
+ bitmap_nr = load_block_bitmap(sb, block_group);
+ if (bitmap_nr < 0)
+ goto error_return;
+ bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
+ ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start);
+
+ if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize)
+ {
+ bit = block % (sb->s_blocksize << 3);
+
+ if (udf_test_bit(bit, bh->b_data))
+ {
+ goto got_block;
+ }
+ end_goal = (bit + 63) & ~63;
+ bit = udf_find_next_one_bit(bh->b_data, end_goal, bit);
+ if (bit < end_goal)
+ goto got_block;
+ ptr = memscan((char *)bh->b_data + (bit >> 3), 0xFF, sb->s_blocksize - ((bit + 7) >> 3));
+ newbit = (ptr - ((char *)bh->b_data)) << 3;
+ if (newbit < sb->s_blocksize << 3)
+ {
+ bit = newbit;
+ goto search_back;
+ }
+ newbit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, bit);
+ if (newbit < sb->s_blocksize << 3)
+ {
+ bit = newbit;
+ goto got_block;
+ }
+ }
+
+ for (i=0; i<(nr_groups*2); i++)
+ {
+ block_group ++;
+ if (block_group >= nr_groups)
+ block_group = 0;
+ group_start = block_group ? 0 : sizeof(struct SpaceBitmapDesc);
+
+ bitmap_nr = load_block_bitmap(sb, block_group);
+ if (bitmap_nr < 0)
+ goto error_return;
+ bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
+ if (i < nr_groups)
+ {
+ ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start);
+ if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize)
+ {
+ bit = (ptr - ((char *)bh->b_data)) << 3;
+ break;
+ }
+ }
+ else
+ {
+ bit = udf_find_next_one_bit((char *)bh->b_data, sb->s_blocksize << 3, group_start << 3);
+ if (bit < sb->s_blocksize << 3)
+ break;
+ }
+ }
+ if (i >= (nr_groups*2))
+ {
+ unlock_super(sb);
+ return newblock;
+ }
+ if (bit < sb->s_blocksize << 3)
+ goto search_back;
+ else
+ bit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, group_start << 3);
+ if (bit >= sb->s_blocksize << 3)
+ {
+ unlock_super(sb);
+ return 0;
+ }
+
+search_back:
+ for (i=0; i<7 && bit > (group_start << 3) && udf_test_bit(bit - 1, bh->b_data); i++, bit--);
+
+got_block:
+ newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) -
+ (group_start << 3);
+
+ tmp = udf_get_pblock(sb, newblock, partition, 0);
+ if (!udf_clear_bit(bit, bh->b_data))
+ {
+ udf_debug("bit already cleared for block %d\n", bit);
+ goto repeat;
+ }
+
+ mark_buffer_dirty(bh, 1);
+ if (!(bh = getblk(sb->s_dev, tmp, sb->s_blocksize)))
+ {
+ udf_debug("cannot get block %d\n", tmp);
+ unlock_super(sb);
+ return 0;
+ }
+ memset(bh->b_data, 0, sb->s_blocksize);
+ mark_buffer_uptodate(bh, 1);
+ mark_buffer_dirty(bh, 1);
+ udf_release_data(bh);
+
+ if (UDF_SB_LVIDBH(sb))
+ {
+ UDF_SB_LVID(sb)->freeSpaceTable[partition] =
+ cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1);
+ mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+ }
+ sb->s_dirt = 1;
+ unlock_super(sb);
+ *err = 0;
+ return newblock;
+
+error_return:
+ *err = -EIO;
+ unlock_super(sb);
+ return 0;
+}
diff --git a/fs/udf/crc.c b/fs/udf/crc.c
new file mode 100644
index 000000000..3e24c7c35
--- /dev/null
+++ b/fs/udf/crc.c
@@ -0,0 +1,178 @@
+/*
+ * crc.c
+ *
+ * PURPOSE
+ * Routines to generate, calculate, and test a 16-bit CRC.
+ *
+ * DESCRIPTION
+ * The CRC code was devised by Don P. Mitchell of AT&T Bell Laboratories
+ * and Ned W. Rhodes of Software Systems Group. It has been published in
+ * "Design and Validation of Computer Protocols", Prentice Hall,
+ * Englewood Cliffs, NJ, 1991, Chapter 3, ISBN 0-13-539925-4.
+ *
+ * Copyright is held by AT&T.
+ *
+ * AT&T gives permission for the free use of the CRC source code.
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ */
+
+#include "udfdecl.h"
+
+static Uint16 crc_table[256] = {
+ 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U,
+ 0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU,
+ 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U,
+ 0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU,
+ 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U,
+ 0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU,
+ 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U,
+ 0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU,
+ 0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U,
+ 0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU,
+ 0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U,
+ 0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU,
+ 0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U,
+ 0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U,
+ 0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U,
+ 0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U,
+ 0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU,
+ 0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U,
+ 0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU,
+ 0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U,
+ 0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU,
+ 0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U,
+ 0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU,
+ 0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U,
+ 0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU,
+ 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U,
+ 0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU,
+ 0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U,
+ 0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U,
+ 0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U,
+ 0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U,
+ 0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U
+};
+
+/*
+ * udf_crc
+ *
+ * PURPOSE
+ * Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial.
+ *
+ * DESCRIPTION
+ * The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory.
+ * The polynomial used is: x^16 + x^12 + x^15 + 1
+ *
+ * PRE-CONDITIONS
+ * data Pointer to the data block.
+ * size Size of the data block.
+ *
+ * POST-CONDITIONS
+ * <return> CRC of the data block.
+ *
+ * HISTORY
+ * July 21, 1997 - Andrew E. Mileski
+ * Adapted from OSTA-UDF(tm) 1.50 standard.
+ */
+extern Uint16
+udf_crc(Uint8 *data, Uint32 size, Uint16 crc)
+{
+ while (size--)
+ crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8);
+
+ return crc;
+}
+
+/****************************************************************************/
+#if defined(TEST)
+
+/*
+ * PURPOSE
+ * Test udf_crc()
+ *
+ * HISTORY
+ * July 21, 1997 - Andrew E. Mileski
+ * Adapted from OSTA-UDF(tm) 1.50 standard.
+ */
+
+unsigned char bytes[] = { 0x70U, 0x6AU, 0x77U };
+
+int main(void)
+{
+ unsigned short x;
+
+ x = udf_crc16(bytes, sizeof bytes);
+ printf("udf_crc16: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U);
+
+ return 0;
+}
+
+#endif /* defined(TEST) */
+
+/****************************************************************************/
+#if defined(GENERATE)
+
+/*
+ * PURPOSE
+ * Generate a table for fast 16-bit CRC calculations (any polynomial).
+ *
+ * DESCRIPTION
+ * The ITU-T V.41 polynomial is 010041.
+ *
+ * HISTORY
+ * July 21, 1997 - Andrew E. Mileski
+ * Adapted from OSTA-UDF(tm) 1.50 standard.
+ */
+
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ unsigned long crc, poly;
+ int n, i;
+
+ /* Get the polynomial */
+ sscanf(argv[1], "%lo", &poly);
+ if (poly & 0xffff0000U){
+ fprintf(stderr, "polynomial is too large\en");
+ exit(1);
+ }
+
+ printf("/* CRC 0%o */\n", poly);
+
+ /* Create a table */
+ printf("static unsigned short crc_table[256] = {\n");
+ for (n = 0; n < 256; n++){
+ if (n % 8 == 0)
+ printf("\t");
+ crc = n << 8;
+ for (i = 0; i < 8; i++){
+ if(crc & 0x8000U)
+ crc = (crc << 1) ^ poly;
+ else
+ crc <<= 1;
+ crc &= 0xFFFFU;
+ }
+ if (n == 255)
+ printf("0x%04xU ", crc);
+ else
+ printf("0x%04xU, ", crc);
+ if(n % 8 == 7)
+ printf("\n");
+ }
+ printf("};\n");
+
+ return 0;
+}
+
+#endif /* defined(GENERATE) */
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
new file mode 100644
index 000000000..50762e5f4
--- /dev/null
+++ b/fs/udf/dir.c
@@ -0,0 +1,296 @@
+/*
+ * dir.c
+ *
+ * PURPOSE
+ * Directory handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ *
+ * (C) 1998-1999 Ben Fennema
+ *
+ * HISTORY
+ *
+ * 10/05/98 dgb Split directory operations into it's own file
+ * Implemented directory reads via do_udf_readdir
+ * 10/06/98 Made directory operations work!
+ * 11/17/98 Rewrote directory to support ICB_FLAG_AD_LONG
+ * 11/25/98 blf Rewrote directory handling (readdir+lookup) to support reading
+ * across blocks.
+ * 12/12/98 Split out the lookup code to namei.c. bulk of directory
+ * code now in directory.c:udf_fileident_read.
+ */
+
+#include "udfdecl.h"
+
+#if defined(__linux__) && defined(__KERNEL__)
+#include <linux/version.h>
+#include "udf_i.h"
+#include "udf_sb.h"
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/udf_fs.h>
+#endif
+
+/* Prototypes for file operations */
+static int udf_readdir(struct file *, void *, filldir_t);
+static int do_udf_readdir(struct inode *, struct file *, filldir_t, void *);
+
+/* readdir and lookup functions */
+
+static struct file_operations udf_dir_operations = {
+ NULL, /* lllseek */
+ NULL, /* read */
+ NULL, /* write */
+ udf_readdir, /* readdir */
+ NULL, /* poll */
+ udf_ioctl, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* open */
+ NULL, /* flush */
+ NULL, /* release */
+ udf_sync_file, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
+};
+
+struct inode_operations udf_dir_inode_operations = {
+ &udf_dir_operations,
+#ifdef CONFIG_UDF_RW
+ udf_create, /* create */
+#else
+ NULL, /* create */
+#endif
+ udf_lookup, /* lookup */
+#ifdef CONFIG_UDF_RW
+ udf_link, /* link */
+ udf_unlink, /* unlink */
+ udf_symlink, /* symlink */
+ udf_mkdir, /* mkdir */
+ udf_rmdir, /* rmdir */
+ udf_mknod, /* mknod */
+ udf_rename, /* rename */
+#else
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+#endif
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* get_block */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* flushpage */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
+};
+
+/*
+ * udf_readdir
+ *
+ * PURPOSE
+ * Read a directory entry.
+ *
+ * DESCRIPTION
+ * Optional - sys_getdents() will return -ENOTDIR if this routine is not
+ * available.
+ *
+ * Refer to sys_getdents() in fs/readdir.c
+ * sys_getdents() -> .
+ *
+ * PRE-CONDITIONS
+ * filp Pointer to directory file.
+ * buf Pointer to directory entry buffer.
+ * filldir Pointer to filldir function.
+ *
+ * POST-CONDITIONS
+ * <return> >=0 on success.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+
+int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ struct inode *dir = filp->f_dentry->d_inode;
+ int result;
+
+ if (!dir)
+ return -EBADF;
+
+ if (!S_ISDIR(dir->i_mode))
+ return -ENOTDIR;
+
+ if ( filp->f_pos == 0 )
+ {
+ if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino) < 0)
+ return 0;
+ }
+
+ result = do_udf_readdir(dir, filp, filldir, dirent);
+ UPDATE_ATIME(dir);
+ return result;
+}
+
+static int
+do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *dirent)
+{
+ struct udf_fileident_bh fibh;
+ struct FileIdentDesc *fi=NULL;
+ struct FileIdentDesc cfi;
+ int block, iblock;
+ int nf_pos = filp->f_pos;
+ int flen;
+ char fname[255];
+ char *nameptr;
+ Uint16 liu;
+ Uint8 lfi;
+ int size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2;
+ struct buffer_head * bh = NULL;
+ lb_addr bloc, eloc;
+ Uint32 extoffset, elen, offset;
+
+ if (nf_pos >= size)
+ return 1;
+
+ if (nf_pos == 0)
+ nf_pos = (UDF_I_EXT0OFFS(dir) >> 2);
+
+ fibh.soffset = fibh.eoffset = (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
+ if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2),
+ &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
+ {
+ block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
+ if (++offset < (elen >> dir->i_sb->s_blocksize_bits))
+ {
+ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
+ extoffset -= sizeof(short_ad);
+ else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG)
+ extoffset -= sizeof(long_ad);
+ }
+ else
+ offset = 0;
+ }
+ else
+ {
+ udf_release_data(bh);
+ return 0;
+ }
+
+ if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+ {
+ udf_release_data(bh);
+ return 0;
+ }
+
+ while ( nf_pos < size )
+ {
+ filp->f_pos = nf_pos;
+
+ fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &bloc, &extoffset, &offset, &bh);
+ liu = le16_to_cpu(cfi.lengthOfImpUse);
+ lfi = cfi.lengthFileIdent;
+
+ if (!fi)
+ {
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+ udf_release_data(bh);
+ return 1;
+ }
+
+ if (fibh.sbh == fibh.ebh)
+ nameptr = fi->fileIdent + liu;
+ else
+ {
+ int poffset; /* Unpaded ending offset */
+
+ poffset = fibh.soffset + sizeof(struct FileIdentDesc) + liu + lfi;
+
+ if (poffset >= lfi)
+ nameptr = (char *)(fibh.ebh->b_data + poffset - lfi);
+ else
+ {
+ nameptr = fname;
+ memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
+ memcpy(nameptr + lfi - poffset, fibh.ebh->b_data, poffset);
+ }
+ }
+
+ if ( (cfi.fileCharacteristics & FILE_DELETED) != 0 )
+ {
+ if ( !IS_UNDELETE(dir->i_sb) )
+ continue;
+ }
+
+ if ( (cfi.fileCharacteristics & FILE_HIDDEN) != 0 )
+ {
+ if ( !IS_UNHIDE(dir->i_sb) )
+ continue;
+ }
+
+ iblock = udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0);
+
+ if (!lfi) /* parent directory */
+ {
+ if (filldir(dirent, "..", 2, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino) < 0)
+ {
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+ udf_release_data(bh);
+ return 1;
+ }
+ }
+ else
+ {
+ if ((flen = udf_get_filename(nameptr, fname, lfi)))
+ {
+ if (filldir(dirent, fname, flen, filp->f_pos, iblock) < 0)
+ {
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+ udf_release_data(bh);
+ return 1; /* halt enum */
+ }
+ }
+ else
+ {
+ udf_debug("size=%d, nf_pos=%d, liu=%d, lfi=%d\n", size, nf_pos, liu, lfi);
+ }
+ }
+ } /* end while */
+
+ filp->f_pos = nf_pos;
+
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+ udf_release_data(bh);
+
+ if ( filp->f_pos >= size)
+ return 1;
+ else
+ return 0;
+}
diff --git a/fs/udf/directory.c b/fs/udf/directory.c
new file mode 100644
index 000000000..bc2ced009
--- /dev/null
+++ b/fs/udf/directory.c
@@ -0,0 +1,332 @@
+/*
+ * directory.c
+ *
+ * PURPOSE
+ * Directory related functions
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ */
+
+#include "udfdecl.h"
+#include "udf_sb.h"
+
+#if defined(__linux__) && defined(__KERNEL__)
+
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/udf_fs.h>
+
+#else
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#endif
+
+#ifdef __KERNEL__
+
+Uint8 * udf_filead_read(struct inode *dir, Uint8 *tmpad, Uint8 ad_size,
+ lb_addr fe_loc, int *pos, int *offset, struct buffer_head **bh, int *error)
+{
+ int loffset = *offset;
+ int block;
+ Uint8 *ad;
+ int remainder;
+
+ *error = 0;
+
+ ad = (Uint8 *)(*bh)->b_data + *offset;
+ *offset += ad_size;
+
+ if (!ad)
+ {
+ udf_release_data(*bh);
+ *error = 1;
+ return NULL;
+ }
+
+ if (*offset == dir->i_sb->s_blocksize)
+ {
+ udf_release_data(*bh);
+ block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
+ if (!block)
+ return NULL;
+ if (!(*bh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+ return NULL;
+ }
+ else if (*offset > dir->i_sb->s_blocksize)
+ {
+ ad = tmpad;
+
+ remainder = dir->i_sb->s_blocksize - loffset;
+ memcpy((Uint8 *)ad, (*bh)->b_data + loffset, remainder);
+
+ udf_release_data(*bh);
+ block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
+ if (!block)
+ return NULL;
+ if (!((*bh) = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+ return NULL;
+
+ memcpy((Uint8 *)ad + remainder, (*bh)->b_data, ad_size - remainder);
+ *offset = ad_size - remainder;
+ }
+ return ad;
+}
+
+struct FileIdentDesc *
+udf_fileident_read(struct inode *dir, int *nf_pos,
+ struct udf_fileident_bh *fibh,
+ struct FileIdentDesc *cfi,
+ lb_addr *bloc, Uint32 *extoffset,
+ Uint32 *offset, struct buffer_head **bh)
+{
+ struct FileIdentDesc *fi;
+ lb_addr eloc;
+ Uint32 elen;
+ int block;
+
+ fibh->soffset = fibh->eoffset;
+
+ if (fibh->eoffset == dir->i_sb->s_blocksize)
+ {
+ int lextoffset = *extoffset;
+
+ if (udf_next_aext(dir, bloc, extoffset, &eloc, &elen, bh, 1) !=
+ EXTENT_RECORDED_ALLOCATED)
+ {
+ return NULL;
+ }
+
+ block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
+
+ (*offset) ++;
+
+ if (*offset >= (elen >> dir->i_sb->s_blocksize_bits))
+ *offset = 0;
+ else
+ *extoffset = lextoffset;
+
+ udf_release_data(fibh->sbh);
+ if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+ return NULL;
+ fibh->soffset = fibh->eoffset = 0;
+ }
+ else if (fibh->sbh != fibh->ebh)
+ {
+ udf_release_data(fibh->sbh);
+ fibh->sbh = fibh->ebh;
+ }
+
+ fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize,
+ &(fibh->eoffset));
+
+ if (!fi)
+ return NULL;
+
+ *nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
+
+ if (fibh->eoffset <= dir->i_sb->s_blocksize)
+ {
+ memcpy((Uint8 *)cfi, (Uint8 *)fi, sizeof(struct FileIdentDesc));
+ }
+ else if (fibh->eoffset > dir->i_sb->s_blocksize)
+ {
+ int lextoffset = *extoffset;
+
+ if (udf_next_aext(dir, bloc, extoffset, &eloc, &elen, bh, 1) !=
+ EXTENT_RECORDED_ALLOCATED)
+ {
+ return NULL;
+ }
+
+ block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
+
+ (*offset) ++;
+
+ if (*offset >= (elen >> dir->i_sb->s_blocksize_bits))
+ *offset = 0;
+ else
+ *extoffset = lextoffset;
+
+ fibh->soffset -= dir->i_sb->s_blocksize;
+ fibh->eoffset -= dir->i_sb->s_blocksize;
+
+ if (!(fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+ return NULL;
+
+ if (sizeof(struct FileIdentDesc) > - fibh->soffset)
+ {
+ int fi_len;
+
+ memcpy((Uint8 *)cfi, (Uint8 *)fi, - fibh->soffset);
+ memcpy((Uint8 *)cfi - fibh->soffset, fibh->ebh->b_data,
+ sizeof(struct FileIdentDesc) + fibh->soffset);
+
+ fi_len = (sizeof(struct FileIdentDesc) + cfi->lengthFileIdent +
+ le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
+
+ *nf_pos += ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2);
+ fibh->eoffset = fibh->soffset + fi_len;
+ }
+ else
+ {
+ memcpy((Uint8 *)cfi, (Uint8 *)fi, sizeof(struct FileIdentDesc));
+ }
+ }
+ return fi;
+}
+#endif
+
+struct FileIdentDesc *
+udf_get_fileident(void * buffer, int bufsize, int * offset)
+{
+ struct FileIdentDesc *fi;
+ int lengthThisIdent;
+ Uint8 * ptr;
+ int padlen;
+
+ if ( (!buffer) || (!offset) ) {
+#ifdef __KERNEL__
+ udf_debug("invalidparms\n, buffer=%p, offset=%p\n", buffer, offset);
+#endif
+ return NULL;
+ }
+
+ ptr = buffer;
+
+ if ( (*offset > 0) && (*offset < bufsize) ) {
+ ptr += *offset;
+ }
+ fi=(struct FileIdentDesc *)ptr;
+ if (le16_to_cpu(fi->descTag.tagIdent) != TID_FILE_IDENT_DESC)
+ {
+#ifdef __KERNEL__
+ udf_debug("0x%x != TID_FILE_IDENT_DESC\n",
+ le16_to_cpu(fi->descTag.tagIdent));
+ udf_debug("offset: %u sizeof: %u bufsize: %u\n",
+ *offset, sizeof(struct FileIdentDesc), bufsize);
+#endif
+ return NULL;
+ }
+ if ( (*offset + sizeof(struct FileIdentDesc)) > bufsize )
+ {
+ lengthThisIdent = sizeof(struct FileIdentDesc);
+ }
+ else
+ lengthThisIdent = sizeof(struct FileIdentDesc) +
+ fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse);
+
+ /* we need to figure padding, too! */
+ padlen = lengthThisIdent % UDF_NAME_PAD;
+ if (padlen)
+ lengthThisIdent += (UDF_NAME_PAD - padlen);
+ *offset = *offset + lengthThisIdent;
+
+ return fi;
+}
+
+extent_ad *
+udf_get_fileextent(void * buffer, int bufsize, int * offset)
+{
+ extent_ad * ext;
+ struct FileEntry *fe;
+ Uint8 * ptr;
+
+ if ( (!buffer) || (!offset) )
+ {
+#ifdef __KERNEL__
+ printk(KERN_ERR "udf: udf_get_fileextent() invalidparms\n");
+#endif
+ return NULL;
+ }
+
+ fe = (struct FileEntry *)buffer;
+
+ if ( le16_to_cpu(fe->descTag.tagIdent) != TID_FILE_ENTRY )
+ {
+#ifdef __KERNEL__
+ udf_debug("0x%x != TID_FILE_ENTRY\n",
+ le16_to_cpu(fe->descTag.tagIdent));
+#endif
+ return NULL;
+ }
+
+ ptr=(Uint8 *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr);
+
+ if ( (*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs)) )
+ {
+ ptr += *offset;
+ }
+
+ ext = (extent_ad *)ptr;
+
+ *offset = *offset + sizeof(extent_ad);
+ return ext;
+}
+
+short_ad *
+udf_get_fileshortad(void * buffer, int maxoffset, int *offset, int inc)
+{
+ short_ad * sa;
+ Uint8 * ptr;
+
+ if ( (!buffer) || (!offset) )
+ {
+#ifdef __KERNEL__
+ printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n");
+#endif
+ return NULL;
+ }
+
+ ptr = (Uint8 *)buffer;
+
+ if ( (*offset > 0) && (*offset < maxoffset) )
+ ptr += *offset;
+ else
+ return NULL;
+
+ if ((sa = (short_ad *)ptr)->extLength == 0)
+ return NULL;
+ else if (inc)
+ (*offset) += sizeof(short_ad);
+ return sa;
+}
+
+long_ad *
+udf_get_filelongad(void * buffer, int maxoffset, int * offset, int inc)
+{
+ long_ad * la;
+ Uint8 * ptr;
+
+ if ( (!buffer) || !(offset) )
+ {
+#ifdef __KERNEL__
+ printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n");
+#endif
+ return NULL;
+ }
+
+ ptr = (Uint8 *)buffer;
+
+ if ( (*offset > 0) && (*offset < maxoffset) )
+ ptr += *offset;
+ else
+ return NULL;
+
+ if ((la = (long_ad *)ptr)->extLength == 0)
+ return NULL;
+ else if (inc)
+ (*offset) += sizeof(long_ad);
+ return la;
+}
diff --git a/fs/udf/file.c b/fs/udf/file.c
new file mode 100644
index 000000000..282466841
--- /dev/null
+++ b/fs/udf/file.c
@@ -0,0 +1,440 @@
+/*
+ * file.c
+ *
+ * PURPOSE
+ * File handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ *
+ * (C) 1998-1999 Dave Boynton
+ * (C) 1998-1999 Ben Fennema
+ * (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ * 10/02/98 dgb Attempt to integrate into udf.o
+ * 10/07/98 Switched to using generic_readpage, etc., like isofs
+ * And it works!
+ * 12/06/98 blf Added udf_file_read. uses generic_file_read for all cases but
+ * ICB_FLAG_AD_IN_ICB.
+ * 04/06/99 64 bit file handling on 32 bit systems taken from ext2 file.c
+ * 05/12/99 Preliminary file write support
+ */
+
+#include "udfdecl.h"
+#include <linux/fs.h>
+#include <linux/udf_fs.h>
+#include <asm/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/string.h> /* memset */
+#include <linux/errno.h>
+#include <linux/locks.h>
+
+#include "udf_i.h"
+#include "udf_sb.h"
+
+#define NBUF 32
+
+typedef void * poll_table;
+
+static long long udf_file_llseek(struct file *, long long, int);
+static ssize_t udf_file_read_adinicb (struct file *, char *, size_t, loff_t *);
+static ssize_t udf_file_write (struct file *, const char *, size_t, loff_t *);
+#if BITS_PER_LONG < 64
+static int udf_open_file(struct inode *, struct file *);
+#endif
+static int udf_release_file(struct inode *, struct file *);
+
+static struct file_operations udf_file_operations = {
+ udf_file_llseek, /* llseek */
+ generic_file_read, /* read */
+ udf_file_write, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ udf_ioctl, /* ioctl */
+ generic_file_mmap, /* mmap */
+#if BITS_PER_LONG == 64
+ NULL, /* open */
+#else
+ udf_open_file, /* open */
+#endif
+ NULL, /* flush */
+ udf_release_file, /* release */
+ udf_sync_file, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
+};
+
+struct inode_operations udf_file_inode_operations = {
+ &udf_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 */
+ udf_get_block, /* get_block */
+ block_read_full_page, /* readpage */
+ block_write_full_page, /* writepage */
+ block_flushpage, /* flushpage */
+#ifdef CONFIG_UDF_RW
+ udf_truncate, /* truncate */
+#else
+ NULL, /* truncate */
+#endif
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
+};
+
+static struct file_operations udf_file_operations_adinicb = {
+ udf_file_llseek, /* llseek */
+ udf_file_read_adinicb,/* read */
+ udf_file_write, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ udf_ioctl, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* open */
+ NULL, /* flush */
+ udf_release_file, /* release */
+ udf_sync_file, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
+};
+
+struct inode_operations udf_file_inode_operations_adinicb = {
+ &udf_file_operations_adinicb,
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ udf_get_block, /* get_block */
+ block_read_full_page, /* readpage */
+ block_write_full_page, /* writepage */
+ block_flushpage, /* flushpage */
+#ifdef CONFIG_UDF_RW
+ udf_truncate, /* truncate */
+#else
+ NULL, /* truncate */
+#endif
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
+};
+
+/*
+ * Make sure the offset never goes beyond the 32-bit mark..
+ */
+static long long udf_file_llseek(struct file * file, long long offset, int origin)
+{
+ struct inode * inode = file->f_dentry->d_inode;
+
+ switch (origin)
+ {
+ case 2:
+ {
+ offset += inode->i_size;
+ break;
+ }
+ case 1:
+ {
+ offset += file->f_pos;
+ break;
+ }
+ }
+#if BITS_PER_LONG < 64
+ if (((unsigned long long) offset >> 32) != 0)
+ {
+ return -EINVAL;
+ }
+#endif
+ if (offset != file->f_pos)
+ {
+ file->f_pos = offset;
+ file->f_reada = 0;
+ file->f_version = ++event;
+ }
+ return offset;
+}
+
+static inline void remove_suid(struct inode * inode)
+{
+ unsigned int mode;
+
+ /* set S_IGID if S_IXGRP is set, and always set S_ISUID */
+ mode = (inode->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID;
+
+ /* was any of the uid bits set? */
+ mode &= inode->i_mode;
+ if (mode && !capable(CAP_FSETID))
+ {
+ inode->i_mode &= ~mode;
+ mark_inode_dirty(inode);
+ }
+}
+
+static ssize_t udf_file_write(struct file * file, const char * buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t retval;
+ struct inode *inode = file->f_dentry->d_inode;
+ remove_suid(inode);
+
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+ {
+ int i, err;
+ struct buffer_head *bh;
+
+ if ((bh = udf_expand_adinicb(inode, &i, 0, &err)))
+ udf_release_data(bh);
+ }
+
+ retval = generic_file_write(file, buf, count, ppos, block_write_partial_page);
+
+ if (retval > 0)
+ {
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ UDF_I_UCTIME(inode) = UDF_I_UMTIME(inode) = CURRENT_UTIME;
+ }
+ mark_inode_dirty(inode);
+ return retval;
+}
+
+/*
+ * udf_file_read
+ *
+ * PURPOSE
+ * Read from an open file.
+ *
+ * DESCRIPTION
+ * Optional - sys_read() will return -EINVAL if this routine is not
+ * available.
+ *
+ * Refer to sys_read() in fs/read_write.c
+ * sys_read() -> .
+ *
+ * Note that you can use generic_file_read() instead, which requires that
+ * udf_readpage() be available, but you can use generic_readpage(), which
+ * requires that udf_block_map() be available. Reading will then be done by
+ * memory-mapping the file a page at a time. This is not suitable for
+ * devices that don't handle read-ahead [example: CD-R/RW that may have
+ * blank sectors that shouldn't be read].
+ *
+ * Refer to generic_file_read() in mm/filemap.c and to generic_readpage()
+ * in fs/buffer.c
+ *
+ * Block devices can use block_read() instead. Refer to fs/block_dev.c
+ *
+ * PRE-CONDITIONS
+ * inode Pointer to inode to read from (never NULL).
+ * filp Pointer to file to read from (never NULL).
+ * buf Point to read buffer (validated).
+ * bufsize Size of read buffer.
+ *
+ * POST-CONDITIONS
+ * <return> Bytes read (>=0) or an error code (<0) that
+ * sys_read() will return.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+static ssize_t udf_file_read_adinicb(struct file * filp, char * buf,
+ size_t bufsize, loff_t * loff)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ Uint32 size, left, pos, block;
+ struct buffer_head *bh = NULL;
+
+ size = inode->i_size;
+ if (*loff > size)
+ left = 0;
+ else
+ left = size - *loff;
+ if (left > bufsize)
+ left = bufsize;
+
+ if (left <= 0)
+ return 0;
+
+ pos = *loff + UDF_I_EXT0OFFS(inode);
+ block = udf_block_map(inode, 0);
+ if (!(bh = udf_tread(inode->i_sb,
+ udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0),
+ inode->i_sb->s_blocksize)))
+ {
+ return 0;
+ }
+ if (!copy_to_user(buf, bh->b_data + pos, left))
+ *loff += left;
+ else
+ return -EFAULT;
+
+ return left;
+}
+
+/*
+ * udf_ioctl
+ *
+ * PURPOSE
+ * Issue an ioctl.
+ *
+ * DESCRIPTION
+ * Optional - sys_ioctl() will return -ENOTTY if this routine is not
+ * available, and the ioctl cannot be handled without filesystem help.
+ *
+ * sys_ioctl() handles these ioctls that apply only to regular files:
+ * FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD
+ * These ioctls are also handled by sys_ioctl():
+ * FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC
+ * All other ioctls are passed to the filesystem.
+ *
+ * Refer to sys_ioctl() in fs/ioctl.c
+ * sys_ioctl() -> .
+ *
+ * PRE-CONDITIONS
+ * inode Pointer to inode that ioctl was issued on.
+ * filp Pointer to file that ioctl was issued on.
+ * cmd The ioctl command.
+ * arg The ioctl argument [can be interpreted as a
+ * user-space pointer if desired].
+ *
+ * POST-CONDITIONS
+ * <return> Success (>=0) or an error code (<=0) that
+ * sys_ioctl() will return.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ int result=-1;
+ int size;
+ struct buffer_head *bh = NULL;
+ struct FileEntry *fe;
+ Uint16 ident;
+
+ if ( permission(inode, MAY_READ) != 0 )
+ {
+ udf_debug("no permission to access inode %lu\n",
+ inode->i_ino);
+ return -EPERM;
+ }
+
+ if ( !arg )
+ {
+ udf_debug("invalid argument to udf_ioctl\n");
+ return -EINVAL;
+ }
+
+ /* first, do ioctls that don't need to udf_read */
+ switch (cmd)
+ {
+ case UDF_GETVOLIDENT:
+ if ( (result == verify_area(VERIFY_WRITE, (char *)arg, 32)) == 0)
+ result = copy_to_user((char *)arg, UDF_SB_VOLIDENT(inode->i_sb), 32);
+ return result;
+
+ }
+
+ /* ok, we need to read the inode */
+ bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
+
+ if (!bh || ident != TID_FILE_ENTRY)
+ {
+ udf_debug("bread failed (ino=%ld) or ident (%d) != TID_FILE_ENTRY",
+ inode->i_ino, ident);
+ return -EFAULT;
+ }
+
+ fe = (struct FileEntry *)bh->b_data;
+ size = le32_to_cpu(fe->lengthExtendedAttr);
+
+ switch (cmd)
+ {
+ case UDF_GETEASIZE:
+ if ( (result = verify_area(VERIFY_WRITE, (char *)arg, 4)) == 0)
+ result= put_user(size, (int *)arg);
+ break;
+
+ case UDF_GETEABLOCK:
+ if ( (result = verify_area(VERIFY_WRITE, (char *)arg, size)) == 0)
+ result= copy_to_user((char *)arg, fe->extendedAttr, size);
+ break;
+
+ default:
+ udf_debug("ino=%ld, cmd=%d\n", inode->i_ino, cmd);
+ break;
+ }
+
+ udf_release_data(bh);
+ return result;
+}
+
+/*
+ * udf_release_file
+ *
+ * PURPOSE
+ * Called when all references to the file are closed
+ *
+ * DESCRIPTION
+ * Discard prealloced blocks
+ *
+ * HISTORY
+ *
+ */
+static int udf_release_file(struct inode * inode, struct file * filp)
+{
+ if (filp->f_mode & FMODE_WRITE)
+ udf_discard_prealloc(inode);
+ return 0;
+}
+
+#if BITS_PER_LONG < 64
+/*
+ * udf_open_file
+ *
+ * PURPOSE
+ * Called when an inode is about to be open.
+ *
+ * DESCRIPTION
+ * Use this to disallow opening RW large files on 32 bit systems.
+ *
+ * HISTORY
+ *
+ */
+static int udf_open_file(struct inode * inode, struct file * filp)
+{
+ if (inode->i_size == (Uint32)-1 && (filp->f_mode & FMODE_WRITE))
+ return -EFBIG;
+ return 0;
+}
+#endif
diff --git a/fs/udf/fsync.c b/fs/udf/fsync.c
new file mode 100644
index 000000000..3e2b95c19
--- /dev/null
+++ b/fs/udf/fsync.c
@@ -0,0 +1,110 @@
+/*
+ * fsync.c
+ *
+ * PURPOSE
+ * Fsync handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ *
+ * (C) 1999 Ben Fennema
+ * (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ * 05/22/99 blf Created.
+ *
+ */
+
+#include "udfdecl.h"
+
+#include <linux/fs.h>
+#include <linux/udf_fs.h>
+#include "udf_i.h"
+
+static int sync_extent_block (struct inode * inode, Uint32 block, int wait)
+{
+ struct buffer_head * bh;
+
+ if (!block)
+ return 0;
+ bh = get_hash_table (inode->i_dev, block, inode->i_sb->s_blocksize);
+ if (!bh)
+ return 0;
+ if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
+ brelse (bh);
+ return -1;
+ }
+ if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
+ brelse (bh);
+ return 0;
+ }
+ ll_rw_block (WRITE, 1, &bh);
+ atomic_dec(&bh->b_count);
+ return 0;
+}
+
+static int sync_all_extents(struct inode * inode, int wait)
+{
+ lb_addr bloc, eloc;
+ Uint32 extoffset, lextoffset, elen, offset, block;
+ int err = 0, etype;
+ struct buffer_head *bh = NULL;
+
+ if ((etype = inode_bmap(inode, 0, &bloc, &extoffset, &eloc, &elen, &offset, &bh)) != -1)
+ {
+ block = udf_get_lb_pblock(inode->i_sb, bloc, 0);
+ err |= sync_extent_block(inode, block, wait);
+ lextoffset = extoffset;
+
+ while ((etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
+ {
+ if (lextoffset > extoffset)
+ {
+ block = udf_get_lb_pblock(inode->i_sb, bloc, 0);
+ err |= sync_extent_block(inode, block, wait);
+ }
+ lextoffset = extoffset;
+ }
+ }
+ udf_release_data(bh);
+ return err;
+}
+
+/*
+ * File may be NULL when we are called. Perhaps we shouldn't
+ * even pass file to fsync ?
+ */
+
+int udf_sync_file(struct file * file, struct dentry *dentry)
+{
+ int wait, err = 0;
+ struct inode *inode = dentry->d_inode;
+
+ if ((S_ISLNK(inode->i_mode) && !(inode->i_blocks)) ||
+ UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+ {
+ /*
+ * Don't sync fast links! or ICB_FLAG_AD_IN_ICB
+ */
+ goto skip;
+ }
+
+ err = generic_buffer_fdatasync(inode, 0, ~0UL);
+
+ for (wait=0; wait<=1; wait++)
+ {
+ err |= sync_all_extents (inode, wait);
+ }
+skip:
+ err |= udf_sync_inode (inode);
+ return err ? -EIO : 0;
+}
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
new file mode 100644
index 000000000..32f60fef5
--- /dev/null
+++ b/fs/udf/ialloc.c
@@ -0,0 +1,169 @@
+/*
+ * ialloc.c
+ *
+ * PURPOSE
+ * Inode allocation handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ *
+ * (C) 1998-1999 Ben Fennema
+ *
+ * HISTORY
+ *
+ * 02/24/99 blf Created.
+ *
+ */
+
+#include "udfdecl.h"
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/udf_fs.h>
+
+#include "udf_i.h"
+#include "udf_sb.h"
+
+void udf_free_inode(struct inode * inode)
+{
+ struct super_block * sb = inode->i_sb;
+ int is_directory;
+ unsigned long ino;
+
+ if (!inode->i_dev)
+ {
+ udf_debug("inode has no device\n");
+ return;
+ }
+ if (inode->i_count > 1)
+ {
+ udf_debug("inode has count=%d\n", inode->i_count);
+ return;
+ }
+ if (inode->i_nlink)
+ {
+ udf_debug("inode has nlink=%d\n", inode->i_nlink);
+ return;
+ }
+ if (!sb)
+ {
+ udf_debug("inode on nonexistent device\n");
+ return;
+ }
+
+ ino = inode->i_ino;
+
+ lock_super(sb);
+
+ is_directory = S_ISDIR(inode->i_mode);
+
+ clear_inode(inode);
+
+ if (UDF_SB_LVIDBH(sb))
+ {
+ if (is_directory)
+ UDF_SB_LVIDIU(sb)->numDirs =
+ cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs) - 1);
+ else
+ UDF_SB_LVIDIU(sb)->numFiles =
+ cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) - 1);
+
+ mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+ }
+
+ unlock_super(sb);
+
+ udf_free_blocks(inode, UDF_I_LOCATION(inode), 0, 1);
+}
+
+struct inode * udf_new_inode (const struct inode *dir, int mode, int * err)
+{
+ struct super_block *sb;
+ struct inode * inode;
+ int block;
+ Uint32 start = UDF_I_LOCATION(dir).logicalBlockNum;
+
+ inode = get_empty_inode();
+ if (!inode)
+ {
+ *err = -ENOMEM;
+ return NULL;
+ }
+ sb = dir->i_sb;
+ inode->i_sb = sb;
+ inode->i_flags = 0;
+ *err = -ENOSPC;
+
+ block = udf_new_block(dir, UDF_I_LOCATION(dir).partitionReferenceNum,
+ start, err);
+ if (*err)
+ {
+ iput(inode);
+ return NULL;
+ }
+ lock_super(sb);
+
+ if (UDF_SB_LVIDBH(sb))
+ {
+ struct LogicalVolHeaderDesc *lvhd;
+ Uint64 uniqueID;
+ lvhd = (struct LogicalVolHeaderDesc *)(UDF_SB_LVID(sb)->logicalVolContentsUse);
+ if (S_ISDIR(mode))
+ UDF_SB_LVIDIU(sb)->numDirs =
+ cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs) + 1);
+ else
+ UDF_SB_LVIDIU(sb)->numFiles =
+ cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) + 1);
+ UDF_I_UNIQUE(inode) = uniqueID = le64_to_cpu(lvhd->uniqueID);
+ if (!(++uniqueID & 0x00000000FFFFFFFFUL))
+ uniqueID += 16;
+ lvhd->uniqueID = cpu_to_le64(uniqueID);
+ mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+ }
+ inode->i_mode = mode;
+ inode->i_sb = sb;
+ inode->i_nlink = 1;
+ inode->i_dev = sb->s_dev;
+ inode->i_uid = current->fsuid;
+ if (dir->i_mode & S_ISGID)
+ {
+ inode->i_gid = dir->i_gid;
+ if (S_ISDIR(mode))
+ mode |= S_ISGID;
+ }
+ else
+ inode->i_gid = current->fsgid;
+ UDF_I_LOCATION(inode).logicalBlockNum = block;
+ UDF_I_LOCATION(inode).partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
+ inode->i_ino = udf_get_lb_pblock(sb, UDF_I_LOCATION(inode), 0);
+ inode->i_blksize = PAGE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_size = 0;
+ UDF_I_LENEATTR(inode) = 0;
+ UDF_I_LENALLOC(inode) = 0;
+ UDF_I_EXT0LOC(inode) = UDF_I_LOCATION(inode);
+ UDF_I_EXT0LEN(inode) = 0;
+#if 1
+ UDF_I_EXT0OFFS(inode) = sizeof(struct FileEntry);
+ UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_IN_ICB;
+#else
+ UDF_I_EXT0OFFS(inode) = 0;
+ UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG;
+#endif
+
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ UDF_I_UMTIME(inode) = UDF_I_UATIME(inode) = UDF_I_UCTIME(inode) = CURRENT_UTIME;
+ inode->i_op = NULL;
+ insert_inode_hash(inode);
+ mark_inode_dirty(inode);
+ unlock_super(sb);
+ *err = 0;
+ return inode;
+}
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
new file mode 100644
index 000000000..5e0aa576e
--- /dev/null
+++ b/fs/udf/inode.c
@@ -0,0 +1,1944 @@
+/*
+ * inode.c
+ *
+ * PURPOSE
+ * Inode handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ *
+ * (C) 1998 Dave Boynton
+ * (C) 1998-1999 Ben Fennema
+ * (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ * 10/04/98 dgb Added rudimentary directory functions
+ * 10/07/98 Fully working udf_block_map! It works!
+ * 11/25/98 bmap altered to better support extents
+ * 12/06/98 blf partition support in udf_iget, udf_block_map and udf_read_inode
+ * 12/12/98 rewrote udf_block_map to handle next extents and descs across
+ * block boundaries (which is not actually allowed)
+ * 12/20/98 added support for strategy 4096
+ * 03/07/99 rewrote udf_block_map (again)
+ * New funcs, inode_bmap, udf_next_aext
+ * 04/19/99 Support for writing device EA's for major/minor #
+ *
+ */
+
+#include "udfdecl.h"
+#include <linux/locks.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+
+#include "udf_i.h"
+#include "udf_sb.h"
+
+#define EXTENT_MERGE_SIZE 5
+
+static mode_t udf_convert_permissions(struct FileEntry *);
+static int udf_update_inode(struct inode *, int);
+static void udf_fill_inode(struct inode *, struct buffer_head *);
+static struct buffer_head *inode_getblk(struct inode *, long, int *, long *, int *);
+static void udf_split_extents(struct inode *, int *, int, int,
+ long_ad [EXTENT_MERGE_SIZE], int *);
+static void udf_prealloc_extents(struct inode *, int, int,
+ long_ad [EXTENT_MERGE_SIZE], int *);
+static void udf_merge_extents(struct inode *,
+ long_ad [EXTENT_MERGE_SIZE], int *);
+static void udf_update_extents(struct inode *,
+ long_ad [EXTENT_MERGE_SIZE], int, int,
+ lb_addr, Uint32, struct buffer_head **);
+
+static DECLARE_MUTEX(read_semaphore);
+
+/*
+ * udf_put_inode
+ *
+ * PURPOSE
+ *
+ * DESCRIPTION
+ * This routine is called whenever the kernel no longer needs the inode.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ *
+ * Called at each iput()
+ */
+void udf_put_inode(struct inode * inode)
+{
+ udf_discard_prealloc(inode);
+}
+
+/*
+ * udf_delete_inode
+ *
+ * PURPOSE
+ * Clean-up before the specified inode is destroyed.
+ *
+ * DESCRIPTION
+ * This routine is called when the kernel destroys an inode structure
+ * ie. when iput() finds i_count == 0.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ *
+ * Called at the last iput() if i_nlink is zero.
+ */
+void udf_delete_inode(struct inode * inode)
+{
+ inode->i_size = 0;
+ if (inode->i_blocks)
+ udf_truncate(inode);
+ udf_free_inode(inode);
+}
+
+void udf_discard_prealloc(struct inode * inode)
+{
+#ifdef UDF_PREALLOCATE
+#if 0
+ unsigned short total;
+ lb_addr loc = UDF_I_LOCATION(inode);
+
+ if (UDF_I_PREALLOC_COUNT(inode))
+ {
+ total = UDF_I_PREALLOC_COUNT(inode);
+ UDF_I_PREALLOC_COUNT(inode) = 0;
+ loc.logicalBlockNum = UDF_I_PREALLOC_BLOCK(inode);
+ udf_free_blocks(inode, loc, 0, total);
+ }
+#endif
+#endif
+}
+
+static int udf_alloc_block(struct inode *inode, Uint16 partition,
+ Uint32 goal, int *err)
+{
+ int result = 0;
+ wait_on_super(inode->i_sb);
+
+ result = udf_new_block(inode, partition, goal, err);
+
+ return result;
+}
+
+struct buffer_head * udf_expand_adinicb(struct inode *inode, int *block, int isdir, int *err)
+{
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+ {
+ long_ad newad;
+ int newblock;
+ struct buffer_head *sbh = NULL, *dbh = NULL;
+
+ if (!UDF_I_LENALLOC(inode))
+ {
+ UDF_I_EXT0OFFS(inode) = 0;
+ UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG;
+ return NULL;
+ }
+
+ /* alloc block, and copy data to it */
+ *block = udf_alloc_block(inode,
+ UDF_I_LOCATION(inode).partitionReferenceNum,
+ UDF_I_LOCATION(inode).logicalBlockNum, err);
+
+ if (!(*block))
+ return NULL;
+ newblock = udf_get_pblock(inode->i_sb, *block,
+ UDF_I_LOCATION(inode).partitionReferenceNum, 0);
+ if (!newblock)
+ return NULL;
+ sbh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+ if (!sbh)
+ return NULL;
+ dbh = udf_tread(inode->i_sb, newblock, inode->i_sb->s_blocksize);
+ if (!dbh)
+ return NULL;
+
+ if (isdir)
+ {
+ struct udf_fileident_bh sfibh, dfibh;
+ int f_pos = UDF_I_EXT0OFFS(inode) >> 2;
+ int size = (UDF_I_EXT0OFFS(inode) + inode->i_size) >> 2;
+ struct FileIdentDesc cfi, *sfi, *dfi;
+
+ sfibh.soffset = sfibh.eoffset = (f_pos & ((inode->i_sb->s_blocksize - 1) >> 2)) << 2;
+ sfibh.sbh = sfibh.ebh = sbh;
+ dfibh.soffset = dfibh.eoffset = 0;
+ dfibh.sbh = dfibh.ebh = dbh;
+ while ( (f_pos < size) )
+ {
+ sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL);
+ if (!sfi)
+ {
+ udf_release_data(sbh);
+ udf_release_data(dbh);
+ return NULL;
+ }
+ sfi->descTag.tagLocation = *block;
+ dfibh.soffset = dfibh.eoffset;
+ dfibh.eoffset += (sfibh.eoffset - sfibh.soffset);
+ dfi = (struct FileIdentDesc *)(dbh->b_data + dfibh.soffset);
+ if (udf_write_fi(sfi, dfi, &dfibh, sfi->impUse,
+ sfi->fileIdent + sfi->lengthOfImpUse))
+ {
+ udf_release_data(sbh);
+ udf_release_data(dbh);
+ return NULL;
+ }
+ }
+ }
+ else
+ {
+ memcpy(dbh->b_data, sbh->b_data + udf_file_entry_alloc_offset(inode),
+ UDF_I_LENALLOC(inode));
+ }
+ mark_buffer_dirty(dbh, 1);
+
+ memset(sbh->b_data + udf_file_entry_alloc_offset(inode),
+ 0, UDF_I_LENALLOC(inode));
+
+ newad.extLength = UDF_I_EXT0LEN(inode) = inode->i_size;
+ newad.extLocation.logicalBlockNum = *block;
+ newad.extLocation.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
+ UDF_I_EXT0LOC(inode) = newad.extLocation;
+ /* UniqueID stuff */
+
+ memcpy(sbh->b_data + udf_file_entry_alloc_offset(inode),
+ &newad, sizeof(newad));
+
+ UDF_I_LENALLOC(inode) = sizeof(newad);
+ UDF_I_EXT0OFFS(inode) = 0;
+ UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG;
+ inode->i_blocks += inode->i_sb->s_blocksize / 512;
+ udf_release_data(sbh);
+ mark_inode_dirty(inode);
+ inode->i_version ++;
+ if (inode->i_op == &udf_file_inode_operations_adinicb)
+ inode->i_op = &udf_file_inode_operations;
+ return dbh;
+ }
+ else
+ return NULL;
+}
+
+struct buffer_head * udf_getblk(struct inode * inode, long block,
+ int create, int * err)
+{
+ struct buffer_head dummy;
+ int error;
+
+ dummy.b_state = 0;
+ dummy.b_blocknr = -1000;
+ error = udf_get_block(inode, block, &dummy, create);
+ *err = error;
+ if (!error & buffer_mapped(&dummy))
+ {
+ struct buffer_head *bh;
+ bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
+ if (buffer_new(&dummy))
+ {
+ memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+ mark_buffer_uptodate(bh, 1);
+ mark_buffer_dirty(bh, 1);
+ }
+ return bh;
+ }
+ return NULL;
+}
+
+int udf_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create)
+{
+ int err, new;
+ struct buffer_head *bh;
+ unsigned long phys;
+
+ if (!create)
+ {
+ phys = udf_block_map(inode, block);
+ if (phys)
+ {
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ }
+ return 0;
+ }
+
+ err = -EIO;
+
+ lock_kernel();
+
+ if (block < 0)
+ goto abort_negative;
+
+ if (block == UDF_I_NEXT_ALLOC_BLOCK(inode) + 1)
+ {
+ UDF_I_NEXT_ALLOC_BLOCK(inode) ++;
+ UDF_I_NEXT_ALLOC_GOAL(inode) ++;
+ }
+
+ err = 0;
+
+ bh = inode_getblk(inode, block, &err, &phys, &new);
+ if (bh)
+ BUG();
+ if (err)
+ goto abort;
+ if (!phys)
+ BUG();
+
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ if (new)
+ bh_result->b_state |= (1UL << BH_New);
+abort:
+ unlock_kernel();
+ return err;
+
+abort_negative:
+ udf_warning(inode->i_sb, "udf_get_block", "block < 0");
+ goto abort;
+}
+
+static struct buffer_head * inode_getblk(struct inode * inode, long block,
+ int *err, long *phys, int *new)
+{
+ struct buffer_head *pbh = NULL, *cbh = NULL, *result = NULL;
+ long_ad laarr[EXTENT_MERGE_SIZE];
+ Uint32 pextoffset = 0, cextoffset = 0, nextoffset = 0;
+ int count = 0, startnum = 0, endnum = 0;
+ Uint32 elen = 0;
+ lb_addr eloc, pbloc = UDF_I_LOCATION(inode), cbloc = UDF_I_LOCATION(inode);
+ int c = 1;
+ int lbcount = 0, b_off = 0, offset = 0;
+ Uint32 newblocknum, newblock;
+ char etype;
+ int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum;
+ char lastblock = 0;
+
+ pextoffset = cextoffset = nextoffset = udf_file_entry_alloc_offset(inode);
+ b_off = block << inode->i_sb->s_blocksize_bits;
+ pbloc = cbloc = UDF_I_LOCATION(inode);
+
+ /* find the extent which contains the block we are looking for.
+ alternate between laarr[0] and laarr[1] for locations of the
+ current extent, and the previous extent */
+ do
+ {
+ if (pbh != cbh)
+ {
+ udf_release_data(pbh);
+ atomic_inc(&cbh->b_count);
+ pbloc = cbloc;
+ }
+
+ lbcount += elen;
+
+ pextoffset = cextoffset;
+ cextoffset = nextoffset;
+
+ if ((etype = udf_next_aext(inode, &cbloc, &nextoffset, &eloc, &elen, &cbh, 1)) == -1)
+ break;
+
+ c = !c;
+
+ laarr[c].extLength = (etype << 30) | elen;
+ laarr[c].extLocation = eloc;
+
+ if (etype != EXTENT_NOT_RECORDED_NOT_ALLOCATED)
+ pgoal = eloc.logicalBlockNum +
+ ((elen + inode->i_sb->s_blocksize - 1) >>
+ inode->i_sb->s_blocksize);
+
+ count ++;
+ } while (lbcount + elen <= b_off);
+
+ b_off -= lbcount;
+ offset = b_off >> inode->i_sb->s_blocksize_bits;
+
+ /* if the extent is allocated and recorded, return the block
+ if the extent is not a multiple of the blocksize, round up */
+
+ if (etype == EXTENT_RECORDED_ALLOCATED)
+ {
+ if (elen & (inode->i_sb->s_blocksize - 1))
+ {
+ elen = (EXTENT_RECORDED_ALLOCATED << 30) |
+ ((elen + inode->i_sb->s_blocksize - 1) &
+ ~(inode->i_sb->s_blocksize - 1));
+ etype = udf_write_aext(inode, cbloc, &cextoffset, eloc, elen, &cbh, 1);
+ }
+ udf_release_data(pbh);
+ udf_release_data(cbh);
+ newblock = udf_get_lb_pblock(inode->i_sb, eloc, offset);
+ *phys = newblock;
+ return NULL;
+ }
+
+ if (etype == -1)
+ {
+ endnum = startnum = ((count > 1) ? 1 : count);
+ c = !c;
+ laarr[c].extLength = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) |
+ ((offset + 1) << inode->i_sb->s_blocksize_bits);
+ memset(&laarr[c].extLocation, 0x00, sizeof(lb_addr));
+ count ++;
+ endnum ++;
+ lastblock = 1;
+ }
+ else
+ endnum = startnum = ((count > 2) ? 2 : count);
+
+ /* if the current extent is in position 0, swap it with the previous */
+ if (!c && count != 1)
+ {
+ laarr[2] = laarr[0];
+ laarr[0] = laarr[1];
+ laarr[1] = laarr[2];
+ c = 1;
+ }
+
+ /* if the current block is located in a extent, read the next extent */
+ if (etype != -1)
+ {
+ if ((etype = udf_next_aext(inode, &cbloc, &nextoffset, &eloc, &elen, &cbh, 0)) != -1)
+ {
+ laarr[c+1].extLength = (etype << 30) | elen;
+ laarr[c+1].extLocation = eloc;
+ count ++;
+ startnum ++;
+ endnum ++;
+ }
+ else
+ lastblock = 1;
+ }
+ udf_release_data(cbh);
+
+ *err = -EFBIG;
+
+ /* Check file limits.. */
+ {
+ unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+ if (limit < RLIM_INFINITY)
+ {
+ limit >>= inode->i_sb->s_blocksize_bits;
+ if (block >= limit)
+ {
+ send_sig(SIGXFSZ, current, 0);
+ *err = -EFBIG;
+ return NULL;
+ }
+ }
+ }
+
+ /* if the current extent is not recorded but allocated, get the
+ block in the extent corresponding to the requested block */
+ if ((laarr[c].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED)
+ newblocknum = laarr[c].extLocation.logicalBlockNum + offset;
+ else /* otherwise, allocate a new block */
+ {
+ if (UDF_I_NEXT_ALLOC_BLOCK(inode) == block)
+ goal = UDF_I_NEXT_ALLOC_GOAL(inode);
+
+ if (!goal)
+ {
+ if (!(goal = pgoal))
+ goal = UDF_I_LOCATION(inode).logicalBlockNum + 1;
+ }
+
+ if (!(newblocknum = udf_alloc_block(inode,
+ UDF_I_LOCATION(inode).partitionReferenceNum, goal, err)))
+ {
+ udf_release_data(pbh);
+ udf_release_data(cbh);
+ *err = -ENOSPC;
+ return NULL;
+ }
+ }
+
+ /* if the extent the requsted block is located in contains multiple blocks,
+ split the extent into at most three extents. blocks prior to requested
+ block, requested block, and blocks after requested block */
+ udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum);
+
+#ifdef UDF_PREALLOCATE
+ /* preallocate blocks */
+ udf_prealloc_extents(inode, c, lastblock, laarr, &endnum);
+#endif
+
+ /* merge any continuous blocks in laarr */
+ udf_merge_extents(inode, laarr, &endnum);
+
+ /* write back the new extents, inserting new extents if the new number
+ of extents is greater than the old number, and deleting extents if
+ the new number of extents is less than the old number */
+ udf_update_extents(inode, laarr, startnum, endnum, pbloc, pextoffset, &pbh);
+
+ udf_release_data(pbh);
+
+ if (c == 0 || c == 1)
+ {
+ UDF_I_EXT0LEN(inode) = laarr[0].extLength;
+ UDF_I_EXT0LOC(inode) = laarr[0].extLocation;
+ }
+
+ if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum,
+ UDF_I_LOCATION(inode).partitionReferenceNum, 0)))
+ {
+ return NULL;
+ }
+ *phys = newblock;
+ *err = 0;
+ *new = 1;
+ UDF_I_NEXT_ALLOC_BLOCK(inode) = block;
+ UDF_I_NEXT_ALLOC_GOAL(inode) = newblocknum;
+ inode->i_ctime = CURRENT_TIME;
+ UDF_I_UCTIME(inode) = CURRENT_UTIME;
+ inode->i_blocks += inode->i_sb->s_blocksize / 512;
+#if 0
+ if (IS_SYNC(inode) || UDF_I_OSYNC(inode))
+ udf_sync_inode(inode);
+ else
+#endif
+ mark_inode_dirty(inode);
+ return result;
+}
+
+static void udf_split_extents(struct inode *inode, int *c, int offset, int newblocknum,
+ long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+{
+ if ((laarr[*c].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED ||
+ (laarr[*c].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED)
+ {
+ int curr = *c;
+ int blen = ((laarr[curr].extLength & UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+ int type = laarr[curr].extLength & ~UDF_EXTENT_LENGTH_MASK;
+
+ if (blen == 1)
+ ;
+ else if (!offset || blen == offset + 1)
+ {
+ laarr[curr+2] = laarr[curr+1];
+ laarr[curr+1] = laarr[curr];
+ }
+ else
+ {
+ laarr[curr+3] = laarr[curr+1];
+ laarr[curr+2] = laarr[curr+1] = laarr[curr];
+ }
+
+ if (offset)
+ {
+ laarr[curr].extLength = type |
+ (offset << inode->i_sb->s_blocksize_bits);
+ curr ++;
+ (*c) ++;
+ (*endnum) ++;
+ }
+
+ laarr[curr].extLocation.logicalBlockNum = newblocknum;
+ if ((type >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED)
+ laarr[curr].extLocation.partitionReferenceNum =
+ UDF_I_LOCATION(inode).partitionReferenceNum;
+ laarr[curr].extLength = (EXTENT_RECORDED_ALLOCATED << 30) |
+ inode->i_sb->s_blocksize;
+ curr ++;
+
+ if (blen != offset + 1)
+ {
+ if ((type >> 30) == EXTENT_NOT_RECORDED_ALLOCATED)
+ laarr[curr].extLocation.logicalBlockNum += (offset + 1);
+ laarr[curr].extLength = type |
+ ((blen - (offset + 1)) << inode->i_sb->s_blocksize_bits);
+ curr ++;
+ (*endnum) ++;
+ }
+ }
+}
+
+static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
+ long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+{
+ int start, length = 0, currlength = 0, i;
+
+ if (*endnum == (c+1) && !lastblock)
+ return;
+
+ if ((laarr[c+1].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED)
+ {
+ start = c+1;
+ length = currlength = (((laarr[c+1].extLength & UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+ }
+ else
+ start = c;
+
+ for (i=start+1; i<=*endnum; i++)
+ {
+ if (i == *endnum)
+ {
+ if (lastblock)
+ length += UDF_DEFAULT_PREALLOC_BLOCKS;
+ }
+ else if ((laarr[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED)
+ length += (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+ else
+ break;
+ }
+
+ if (length)
+ {
+ int next = laarr[start].extLocation.logicalBlockNum +
+ (((laarr[start].extLength & UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+ int numalloc = udf_alloc_blocks(inode,
+ laarr[start].extLocation.partitionReferenceNum,
+ next, (UDF_DEFAULT_PREALLOC_BLOCKS > length ? length :
+ UDF_DEFAULT_PREALLOC_BLOCKS) - currlength);
+
+ if (numalloc)
+ {
+ if (start == (c+1))
+ laarr[start].extLength +=
+ (numalloc << inode->i_sb->s_blocksize_bits);
+ else
+ {
+ memmove(&laarr[c+2], &laarr[c+1],
+ sizeof(long_ad) * (*endnum - (c+1)));
+ (*endnum) ++;
+ laarr[c+1].extLocation.logicalBlockNum = next;
+ laarr[c+1].extLocation.partitionReferenceNum =
+ laarr[c].extLocation.partitionReferenceNum;
+ laarr[c+1].extLength = (EXTENT_NOT_RECORDED_ALLOCATED << 30) |
+ (numalloc << inode->i_sb->s_blocksize_bits);
+ start = c+1;
+ }
+
+ for (i=start+1; numalloc && i<*endnum; i++)
+ {
+ int elen = ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+
+ if (elen > numalloc)
+ {
+ laarr[c+1].extLength -=
+ (numalloc << inode->i_sb->s_blocksize_bits);
+ numalloc = 0;
+ }
+ else
+ {
+ numalloc -= elen;
+ if (*endnum > (i+1))
+ memmove(&laarr[i], &laarr[i+1],
+ sizeof(long_ad) * (*endnum - (i+1)));
+ i --;
+ (*endnum) --;
+ }
+ }
+ }
+ }
+}
+
+static void udf_merge_extents(struct inode *inode,
+ long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+{
+ int i;
+
+ for (i=0; i<(*endnum-1); i++)
+ {
+ if ((laarr[i].extLength >> 30) == (laarr[i+1].extLength >> 30))
+ {
+ if (((laarr[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) ||
+ ((laarr[i+1].extLocation.logicalBlockNum - laarr[i].extLocation.logicalBlockNum) ==
+ (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits)))
+ {
+ laarr[i].extLength = laarr[i+1].extLength +
+ (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize-1));
+ if (*endnum > (i+2))
+ memmove(&laarr[i+1], &laarr[i+2],
+ sizeof(long_ad) * (*endnum - (i+2)));
+ i --;
+ (*endnum) --;
+ }
+ }
+ }
+}
+
+static void udf_update_extents(struct inode *inode,
+ long_ad laarr[EXTENT_MERGE_SIZE], int startnum, int endnum,
+ lb_addr pbloc, Uint32 pextoffset, struct buffer_head **pbh)
+{
+ int start = 0, i;
+ lb_addr tmploc;
+ Uint32 tmplen;
+
+ if (startnum > endnum)
+ {
+ for (i=0; i<(startnum-endnum); i++)
+ {
+ udf_delete_aext(inode, pbloc, pextoffset, laarr[i].extLocation,
+ laarr[i].extLength, *pbh);
+ }
+ }
+ else if (startnum < endnum)
+ {
+ for (i=0; i<(endnum-startnum); i++)
+ {
+ udf_insert_aext(inode, pbloc, pextoffset, laarr[i].extLocation,
+ laarr[i].extLength, *pbh);
+ udf_next_aext(inode, &pbloc, &pextoffset, &laarr[i].extLocation,
+ &laarr[i].extLength, pbh, 1);
+ start ++;
+ }
+ }
+
+ for (i=start; i<endnum; i++)
+ {
+ udf_next_aext(inode, &pbloc, &pextoffset, &tmploc, &tmplen, pbh, 0);
+ udf_write_aext(inode, pbloc, &pextoffset, laarr[i].extLocation,
+ laarr[i].extLength, pbh, 1);
+ }
+}
+
+struct buffer_head * udf_bread(struct inode * inode, int block,
+ int create, int * err)
+{
+ struct buffer_head * bh = NULL;
+ int prev_blocks;
+
+ prev_blocks = inode->i_blocks;
+
+ bh = udf_getblk(inode, block, create, err);
+ if (!bh)
+ return NULL;
+
+#if 0
+ if (create &&
+ S_ISDIR(inode->i_mode) &&
+ inode->i_blocks > prev_blocks)
+ {
+ int i;
+ struct buffer_head *tmp_bh = NULL;
+
+ for (i=1;
+ i < UDF_DEFAULT_PREALLOC_DIR_BLOCKS;
+ i++)
+ {
+ tmp_bh = udf_getblk(inode, block+i, create, err);
+ if (!tmp_bh)
+ {
+ udf_release_data(bh);
+ return 0;
+ }
+ udf_release_data(tmp_bh);
+ }
+ }
+#endif
+
+ if (buffer_uptodate(bh))
+ return bh;
+ ll_rw_block(READ, 1, &bh);
+ wait_on_buffer(bh);
+ if (buffer_uptodate(bh))
+ return bh;
+ brelse(bh);
+ *err = -EIO;
+ return NULL;
+}
+
+/*
+ * udf_read_inode
+ *
+ * PURPOSE
+ * Read an inode.
+ *
+ * DESCRIPTION
+ * This routine is called by iget() [which is called by udf_iget()]
+ * (clean_inode() will have been called first)
+ * when an inode is first read into memory.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ *
+ * 12/19/98 dgb Updated to fix size problems.
+ */
+void
+udf_read_inode(struct inode *inode)
+{
+ struct buffer_head *bh = NULL;
+ struct FileEntry *fe;
+ Uint16 ident;
+
+ /*
+ * Set defaults, but the inode is still incomplete!
+ * Note: get_new_inode() sets the following on a new inode:
+ * i_sb = sb
+ * i_dev = sb->s_dev;
+ * i_no = ino
+ * i_flags = sb->s_flags
+ * i_state = 0
+ * clean_inode(): zero fills and sets
+ * i_count = 1
+ * i_nlink = 1
+ * i_op = NULL;
+ */
+
+ inode->i_blksize = inode->i_sb->s_blocksize;
+ inode->i_version = 1;
+
+ UDF_I_EXT0LEN(inode)=0;
+ UDF_I_EXT0LOC(inode).logicalBlockNum = 0xFFFFFFFF;
+ UDF_I_EXT0LOC(inode).partitionReferenceNum = 0xFFFF;
+ UDF_I_EXT0OFFS(inode)=0;
+ UDF_I_ALLOCTYPE(inode)=0;
+
+ memcpy(&UDF_I_LOCATION(inode), &UDF_SB_LOCATION(inode->i_sb), sizeof(lb_addr));
+
+ bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
+
+ if (!bh)
+ {
+ printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed !bh\n",
+ inode->i_ino);
+ make_bad_inode(inode);
+ return;
+ }
+
+ if (ident != TID_FILE_ENTRY && ident != TID_EXTENDED_FILE_ENTRY)
+ {
+ printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed ident=%d\n",
+ inode->i_ino, ident);
+ udf_release_data(bh);
+ make_bad_inode(inode);
+ return;
+ }
+
+ fe = (struct FileEntry *)bh->b_data;
+
+ if (le16_to_cpu(fe->icbTag.strategyType) == 4096)
+ {
+ struct buffer_head *ibh = NULL, *nbh = NULL;
+ struct IndirectEntry *ie;
+
+ ibh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 1, &ident);
+ if (ident == TID_INDIRECT_ENTRY)
+ {
+ if (ibh)
+ {
+ lb_addr loc;
+ ie = (struct IndirectEntry *)ibh->b_data;
+
+ loc = lelb_to_cpu(ie->indirectICB.extLocation);
+
+ if (ie->indirectICB.extLength &&
+ (nbh = udf_read_ptagged(inode->i_sb, loc, 0, &ident)))
+ {
+ if (ident == TID_FILE_ENTRY ||
+ ident == TID_EXTENDED_FILE_ENTRY)
+ {
+ memcpy(&UDF_SB_LOCATION(inode->i_sb), &loc, sizeof(lb_addr));
+ udf_release_data(bh);
+ udf_release_data(ibh);
+ udf_release_data(nbh);
+ udf_read_inode(inode);
+ return;
+ }
+ else
+ {
+ udf_release_data(nbh);
+ udf_release_data(ibh);
+ }
+ }
+ else
+ udf_release_data(ibh);
+ }
+ }
+ else
+ udf_release_data(ibh);
+ }
+ else if (le16_to_cpu(fe->icbTag.strategyType) != 4)
+ {
+ printk(KERN_ERR "udf: unsupported strategy type: %d\n",
+ le16_to_cpu(fe->icbTag.strategyType));
+ udf_release_data(bh);
+ make_bad_inode(inode);
+ return;
+ }
+ udf_fill_inode(inode, bh);
+ udf_release_data(bh);
+}
+
+static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
+{
+ struct FileEntry *fe;
+ struct ExtendedFileEntry *efe;
+ time_t convtime;
+ int offset, alen;
+
+ fe = (struct FileEntry *)bh->b_data;
+ efe = (struct ExtendedFileEntry *)bh->b_data;
+
+ if (fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY)
+ UDF_I_EXTENDED_FE(inode) = 1;
+ else /* fe->descTag.tagIdent == TID_FILE_ENTRY */
+ UDF_I_EXTENDED_FE(inode) = 0;
+
+ if (le16_to_cpu(fe->icbTag.strategyType) == 4)
+ UDF_I_STRAT4096(inode) = 0;
+ else /* if (le16_to_cpu(fe->icbTag.strategyType) == 4096) */
+ UDF_I_STRAT4096(inode) = 1;
+
+ inode->i_uid = udf_convert_uid(le32_to_cpu(fe->uid));
+ if ( !inode->i_uid ) inode->i_uid = UDF_SB(inode->i_sb)->s_uid;
+
+ inode->i_gid = udf_convert_gid(le32_to_cpu(fe->gid));
+ if ( !inode->i_gid ) inode->i_gid = UDF_SB(inode->i_sb)->s_gid;
+
+ inode->i_nlink = le16_to_cpu(fe->fileLinkCount);
+ if (!inode->i_nlink)
+ inode->i_nlink = 1;
+
+ inode->i_size = le64_to_cpu(fe->informationLength);
+#if BITS_PER_LONG < 64
+ if (le64_to_cpu(fe->informationLength) & 0xFFFFFFFF00000000)
+ inode->i_size = (Uint32)-1;
+#endif
+
+ inode->i_mode = udf_convert_permissions(fe);
+ inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask;
+
+#ifdef UDF_PREALLOCATE
+#if 0
+ UDF_I_PREALLOC_BLOCK(inode) = 0;
+ UDF_I_PREALLOC_COUNT(inode) = 0;
+#endif
+#endif
+ UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
+ UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
+
+ UDF_I_ALLOCTYPE(inode) = le16_to_cpu(fe->icbTag.flags) & ICB_FLAG_ALLOC_MASK;
+
+ if (UDF_I_EXTENDED_FE(inode) == 0)
+ {
+ inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
+ (inode->i_sb->s_blocksize_bits - 9);
+
+ if ( udf_stamp_to_time(&convtime, lets_to_cpu(fe->modificationTime)) )
+ {
+ inode->i_mtime = convtime;
+ inode->i_ctime = convtime;
+ }
+ else
+ {
+ inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb);
+ inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb);
+ }
+
+ if ( udf_stamp_to_time(&convtime, lets_to_cpu(fe->accessTime)) )
+ inode->i_atime = convtime;
+ else
+ inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb);
+
+ UDF_I_UNIQUE(inode) = le64_to_cpu(fe->uniqueID);
+ UDF_I_LENEATTR(inode) = le32_to_cpu(fe->lengthExtendedAttr);
+ UDF_I_LENALLOC(inode) = le32_to_cpu(fe->lengthAllocDescs);
+ offset = sizeof(struct FileEntry) + UDF_I_LENEATTR(inode);
+ alen = offset + UDF_I_LENALLOC(inode);
+ }
+ else
+ {
+ inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
+ (inode->i_sb->s_blocksize_bits - 9);
+
+ if ( udf_stamp_to_time(&convtime, lets_to_cpu(efe->modificationTime)) )
+ inode->i_mtime = convtime;
+ else
+ inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb);
+
+ if ( udf_stamp_to_time(&convtime, lets_to_cpu(efe->accessTime)) )
+ inode->i_atime = convtime;
+ else
+ inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb);
+
+ if ( udf_stamp_to_time(&convtime, lets_to_cpu(efe->createTime)) )
+ inode->i_ctime = convtime;
+ else
+ inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb);
+
+ UDF_I_UNIQUE(inode) = le64_to_cpu(efe->uniqueID);
+ UDF_I_LENEATTR(inode) = le32_to_cpu(efe->lengthExtendedAttr);
+ UDF_I_LENALLOC(inode) = le32_to_cpu(efe->lengthAllocDescs);
+ offset = sizeof(struct ExtendedFileEntry) + UDF_I_LENEATTR(inode);
+ alen = offset + UDF_I_LENALLOC(inode);
+ }
+
+ switch (UDF_I_ALLOCTYPE(inode))
+ {
+ case ICB_FLAG_AD_SHORT:
+ {
+ short_ad * sa;
+
+ sa = udf_get_fileshortad(fe, alen, &offset, 1);
+ if (sa)
+ {
+ UDF_I_EXT0LEN(inode) = le32_to_cpu(sa->extLength);
+ UDF_I_EXT0LOC(inode).logicalBlockNum = le32_to_cpu(sa->extPosition);
+ UDF_I_EXT0LOC(inode).partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
+ }
+ break;
+ }
+ case ICB_FLAG_AD_LONG:
+ {
+ long_ad * la;
+
+ la = udf_get_filelongad(fe, alen, &offset, 1);
+ if (la)
+ {
+ UDF_I_EXT0LEN(inode) = le32_to_cpu(la->extLength);
+ UDF_I_EXT0LOC(inode).logicalBlockNum = le32_to_cpu(la->extLocation.logicalBlockNum);
+ UDF_I_EXT0LOC(inode).partitionReferenceNum = le16_to_cpu(la->extLocation.partitionReferenceNum);
+ }
+ break;
+ }
+ case ICB_FLAG_AD_EXTENDED:
+ {
+ extent_ad * ext;
+
+ ext = udf_get_fileextent(fe, alen, &offset);
+ if ( (ext) && (ext->extLength) )
+ {
+ UDF_I_EXT0LEN(inode) = le32_to_cpu(ext->extLength);
+#if 0
+ UDF_I_EXT0LOC(inode) = ext->extLocation;
+#endif
+ }
+ break;
+ }
+ case ICB_FLAG_AD_IN_ICB: /* short directories */
+ {
+ UDF_I_EXT0LEN(inode) = le32_to_cpu(fe->lengthAllocDescs);
+ UDF_I_EXT0LOC(inode) = UDF_I_LOCATION(inode);
+ UDF_I_EXT0OFFS(inode) = sizeof(struct FileEntry) +
+ le32_to_cpu(fe->lengthExtendedAttr);
+ break;
+ }
+ } /* end switch ad_type */
+
+ switch (fe->icbTag.fileType)
+ {
+ case FILE_TYPE_DIRECTORY:
+ {
+ inode->i_op = &udf_dir_inode_operations;
+ inode->i_mode |= S_IFDIR;
+ inode->i_nlink ++;
+ break;
+ }
+ case FILE_TYPE_REGULAR:
+ case FILE_TYPE_NONE:
+ {
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+ inode->i_op = &udf_file_inode_operations_adinicb;
+ else
+ inode->i_op = &udf_file_inode_operations;
+ inode->i_mode |= S_IFREG;
+ break;
+ }
+ case FILE_TYPE_BLOCK:
+ {
+ inode->i_op = &blkdev_inode_operations;
+ inode->i_mode |= S_IFBLK;
+ break;
+ }
+ case FILE_TYPE_CHAR:
+ {
+ inode->i_op = &chrdev_inode_operations;
+ inode->i_mode |= S_IFCHR;
+ break;
+ }
+ case FILE_TYPE_FIFO:
+ {
+ init_fifo(inode);
+ }
+ case FILE_TYPE_SYMLINK:
+ {
+ /* untested! */
+ inode->i_op = &udf_symlink_inode_operations;
+ inode->i_mode = S_IFLNK|S_IRWXUGO;
+ break;
+ }
+ default:
+ {
+ printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown file type=%d\n",
+ inode->i_ino, fe->icbTag.fileType);
+ make_bad_inode(inode);
+ return;
+ }
+ }
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ {
+ struct buffer_head *tbh = NULL;
+ struct DeviceSpecificationExtendedAttr *dsea =
+ (struct DeviceSpecificationExtendedAttr *)
+ udf_get_extendedattr(inode, 12, 1, &tbh);
+
+ if (dsea)
+ {
+ inode->i_rdev = to_kdev_t(
+ (le32_to_cpu(dsea->majorDeviceIdent)) << 8) |
+ (le32_to_cpu(dsea->minorDeviceIdent) & 0xFF);
+ /* Developer ID ??? */
+ udf_release_data(tbh);
+ }
+ else
+ {
+ make_bad_inode(inode);
+ }
+ }
+}
+
+static mode_t
+udf_convert_permissions(struct FileEntry *fe)
+{
+ mode_t mode;
+ Uint32 permissions;
+ Uint32 flags;
+
+ permissions = le32_to_cpu(fe->permissions);
+ flags = le16_to_cpu(fe->icbTag.flags);
+
+ mode = (( permissions ) & S_IRWXO) |
+ (( permissions >> 2 ) & S_IRWXG) |
+ (( permissions >> 4 ) & S_IRWXU) |
+ (( flags & ICB_FLAG_SETUID) ? S_ISUID : 0) |
+ (( flags & ICB_FLAG_SETGID) ? S_ISGID : 0) |
+ (( flags & ICB_FLAG_STICKY) ? S_ISVTX : 0);
+
+ return mode;
+}
+
+/*
+ * udf_write_inode
+ *
+ * PURPOSE
+ * Write out the specified inode.
+ *
+ * DESCRIPTION
+ * This routine is called whenever an inode is synced.
+ * Currently this routine is just a placeholder.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+
+void udf_write_inode(struct inode * inode)
+{
+ udf_update_inode(inode, 0);
+}
+
+int udf_sync_inode(struct inode * inode)
+{
+ return udf_update_inode(inode, 1);
+}
+
+static int
+udf_update_inode(struct inode *inode, int do_sync)
+{
+ struct buffer_head *bh = NULL;
+ struct FileEntry *fe;
+ struct ExtendedFileEntry *efe;
+ Uint32 udfperms;
+ Uint16 icbflags;
+ Uint16 crclen;
+ int i;
+ timestamp cpu_time;
+ int err = 0;
+
+ bh = udf_tread(inode->i_sb,
+ udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0),
+ inode->i_sb->s_blocksize);
+ if (!bh)
+ {
+ udf_debug("bread failure\n");
+ return -EIO;
+ }
+ fe = (struct FileEntry *)bh->b_data;
+ efe = (struct ExtendedFileEntry *)bh->b_data;
+
+ if (inode->i_uid != UDF_SB(inode->i_sb)->s_uid)
+ fe->uid = cpu_to_le32(inode->i_uid);
+
+ if (inode->i_gid != UDF_SB(inode->i_sb)->s_gid)
+ fe->gid = cpu_to_le32(inode->i_gid);
+
+ udfperms = ((inode->i_mode & S_IRWXO) ) |
+ ((inode->i_mode & S_IRWXG) << 2) |
+ ((inode->i_mode & S_IRWXU) << 4);
+
+ udfperms |= (le32_to_cpu(fe->permissions) &
+ (PERM_O_DELETE | PERM_O_CHATTR |
+ PERM_G_DELETE | PERM_G_CHATTR |
+ PERM_U_DELETE | PERM_U_CHATTR));
+ fe->permissions = cpu_to_le32(udfperms);
+
+ if (S_ISDIR(inode->i_mode))
+ fe->fileLinkCount = cpu_to_le16(inode->i_nlink - 1);
+ else
+ fe->fileLinkCount = cpu_to_le16(inode->i_nlink);
+
+
+ fe->informationLength = cpu_to_le64(inode->i_size);
+
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ {
+ EntityID *eid;
+ struct buffer_head *tbh = NULL;
+ struct DeviceSpecificationExtendedAttr *dsea =
+ (struct DeviceSpecificationExtendedAttr *)
+ udf_get_extendedattr(inode, 12, 1, &tbh);
+
+ if (!dsea)
+ {
+ dsea = (struct DeviceSpecificationExtendedAttr *)
+ udf_add_extendedattr(inode,
+ sizeof(struct DeviceSpecificationExtendedAttr) +
+ sizeof(EntityID), 12, 0x3, &tbh);
+ dsea->attrType = 12;
+ dsea->attrSubtype = 1;
+ dsea->attrLength = sizeof(struct DeviceSpecificationExtendedAttr) +
+ sizeof(EntityID);
+ dsea->impUseLength = sizeof(EntityID);
+ }
+ eid = (EntityID *)dsea->impUse;
+ memset(eid, 0, sizeof(EntityID));
+ strcpy(eid->ident, UDF_ID_DEVELOPER);
+ eid->identSuffix[0] = UDF_OS_CLASS_UNIX;
+ eid->identSuffix[1] = UDF_OS_ID_LINUX;
+ dsea->majorDeviceIdent = kdev_t_to_nr(inode->i_rdev) >> 8;
+ dsea->minorDeviceIdent = kdev_t_to_nr(inode->i_rdev) & 0xFF;
+ mark_buffer_dirty(tbh, 1);
+ udf_release_data(tbh);
+ }
+
+ if (UDF_I_EXTENDED_FE(inode) == 0)
+ {
+ fe->logicalBlocksRecorded = cpu_to_le64(
+ (inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >>
+ (inode->i_sb->s_blocksize_bits - 9));
+
+ if (udf_time_to_stamp(&cpu_time, inode->i_atime, UDF_I_UATIME(inode)))
+ fe->accessTime = cpu_to_lets(cpu_time);
+ if (udf_time_to_stamp(&cpu_time, inode->i_mtime, UDF_I_UMTIME(inode)))
+ fe->modificationTime = cpu_to_lets(cpu_time);
+ memset(&(fe->impIdent), 0, sizeof(EntityID));
+ strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER);
+ fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
+ fe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
+ fe->uniqueID = cpu_to_le64(UDF_I_UNIQUE(inode));
+ fe->lengthExtendedAttr = cpu_to_le32(UDF_I_LENEATTR(inode));
+ fe->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
+ fe->descTag.tagIdent = le16_to_cpu(TID_FILE_ENTRY);
+ crclen = sizeof(struct FileEntry);
+ }
+ else
+ {
+ efe->logicalBlocksRecorded = cpu_to_le64(
+ (inode->i_blocks + (2 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >>
+ (inode->i_sb->s_blocksize_bits - 9));
+
+ if (udf_time_to_stamp(&cpu_time, inode->i_atime, UDF_I_UATIME(inode)))
+ efe->accessTime = cpu_to_lets(cpu_time);
+ if (udf_time_to_stamp(&cpu_time, inode->i_mtime, UDF_I_UMTIME(inode)))
+ efe->modificationTime = cpu_to_lets(cpu_time);
+ if (udf_time_to_stamp(&cpu_time, inode->i_ctime, UDF_I_UCTIME(inode)))
+ efe->createTime = cpu_to_lets(cpu_time);
+ memset(&(efe->impIdent), 0, sizeof(EntityID));
+ strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER);
+ efe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
+ efe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
+ efe->uniqueID = cpu_to_le64(UDF_I_UNIQUE(inode));
+ efe->lengthExtendedAttr = cpu_to_le32(UDF_I_LENEATTR(inode));
+ efe->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
+ efe->descTag.tagIdent = le16_to_cpu(TID_EXTENDED_FILE_ENTRY);
+ crclen = sizeof(struct ExtendedFileEntry);
+ }
+ fe->icbTag.strategyType = UDF_I_STRAT4096(inode) ? cpu_to_le16(4096) :
+ cpu_to_le16(4);
+
+ if (S_ISDIR(inode->i_mode))
+ fe->icbTag.fileType = FILE_TYPE_DIRECTORY;
+ else if (S_ISREG(inode->i_mode))
+ fe->icbTag.fileType = FILE_TYPE_REGULAR;
+ else if (S_ISLNK(inode->i_mode))
+ fe->icbTag.fileType = FILE_TYPE_SYMLINK;
+ else if (S_ISBLK(inode->i_mode))
+ fe->icbTag.fileType = FILE_TYPE_BLOCK;
+ else if (S_ISCHR(inode->i_mode))
+ fe->icbTag.fileType = FILE_TYPE_CHAR;
+ else if (S_ISFIFO(inode->i_mode))
+ fe->icbTag.fileType = FILE_TYPE_FIFO;
+
+ icbflags = UDF_I_ALLOCTYPE(inode) |
+ ((inode->i_mode & S_ISUID) ? ICB_FLAG_SETUID : 0) |
+ ((inode->i_mode & S_ISGID) ? ICB_FLAG_SETGID : 0) |
+ ((inode->i_mode & S_ISVTX) ? ICB_FLAG_STICKY : 0) |
+ (le16_to_cpu(fe->icbTag.flags) &
+ ~(ICB_FLAG_ALLOC_MASK | ICB_FLAG_SETUID |
+ ICB_FLAG_SETGID | ICB_FLAG_STICKY));
+
+ fe->icbTag.flags = cpu_to_le16(icbflags);
+ fe->descTag.descVersion = cpu_to_le16(2);
+ fe->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb));
+ fe->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
+ crclen += UDF_I_LENEATTR(inode) + UDF_I_LENALLOC(inode) - sizeof(tag);
+ fe->descTag.descCRCLength = cpu_to_le16(crclen);
+ fe->descTag.descCRC = cpu_to_le16(udf_crc((char *)fe + sizeof(tag), crclen, 0));
+
+ fe->descTag.tagChecksum = 0;
+ for (i=0; i<16; i++)
+ if (i != 4)
+ fe->descTag.tagChecksum += ((Uint8 *)&(fe->descTag))[i];
+
+ /* write the data blocks */
+ mark_buffer_dirty(bh, 1);
+ if (do_sync)
+ {
+ ll_rw_block(WRITE, 1, &bh);
+ wait_on_buffer(bh);
+ if (buffer_req(bh) && !buffer_uptodate(bh))
+ {
+ printk("IO error syncing udf inode [%s:%08lx]\n",
+ bdevname(inode->i_dev), inode->i_ino);
+ err = -EIO;
+ }
+ }
+ udf_release_data(bh);
+ return err;
+}
+
+/*
+ * udf_iget
+ *
+ * PURPOSE
+ * Get an inode.
+ *
+ * DESCRIPTION
+ * This routine replaces iget() and read_inode().
+ *
+ * HISTORY
+ * October 3, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ *
+ * 12/19/98 dgb Added semaphore and changed to be a wrapper of iget
+ */
+struct inode *
+udf_iget(struct super_block *sb, lb_addr ino)
+{
+ struct inode *inode;
+ unsigned long block;
+
+ block = udf_get_lb_pblock(sb, ino, 0);
+
+ down(&read_semaphore); /* serialize access to UDF_SB_LOCATION() */
+ /* This is really icky.. should fix -- blf */
+
+ /* put the location where udf_read_inode can find it */
+ memcpy(&UDF_SB_LOCATION(sb), &ino, sizeof(lb_addr));
+
+ /* Get the inode */
+
+ inode = iget(sb, block);
+ /* calls udf_read_inode() ! */
+
+ up(&read_semaphore);
+
+ if (!inode)
+ {
+ printk(KERN_ERR "udf: iget() failed\n");
+ return NULL;
+ }
+ else if (is_bad_inode(inode))
+ {
+ iput(inode);
+ return NULL;
+ }
+
+ if ( ino.logicalBlockNum >= UDF_SB_PARTLEN(sb, ino.partitionReferenceNum) )
+ {
+ udf_debug("block=%d, partition=%d out of range\n",
+ ino.logicalBlockNum, ino.partitionReferenceNum);
+ return NULL;
+ }
+
+ return inode;
+}
+
+int udf_add_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
+ lb_addr eloc, Uint32 elen, struct buffer_head **bh, int inc)
+{
+ int adsize;
+ short_ad *sad = NULL;
+ long_ad *lad = NULL;
+ struct AllocExtDesc *aed;
+ int ret;
+
+ if (!(*bh))
+ {
+ if (!(*bh = udf_tread(inode->i_sb,
+ udf_get_lb_pblock(inode->i_sb, *bloc, 0),
+ inode->i_sb->s_blocksize)))
+ {
+ udf_debug("reading block %d failed!\n",
+ udf_get_lb_pblock(inode->i_sb, *bloc, 0));
+ return -1;
+ }
+ }
+
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+ adsize = sizeof(short_ad);
+ else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+ adsize = sizeof(long_ad);
+ else
+ return -1;
+
+ if (*extoffset + (2 * adsize) > inode->i_sb->s_blocksize)
+ {
+ char *sptr, *dptr;
+ struct buffer_head *nbh;
+ int err, loffset;
+ Uint32 lblock = bloc->logicalBlockNum;
+ Uint16 lpart = bloc->partitionReferenceNum;
+
+ if (!(bloc->logicalBlockNum = udf_new_block(inode,
+ lpart, lblock, &err)))
+ {
+ return -1;
+ }
+ if (!(nbh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
+ *bloc, 0), inode->i_sb->s_blocksize)))
+ {
+ return -1;
+ }
+ aed = (struct AllocExtDesc *)(nbh->b_data);
+ aed->previousAllocExtLocation = cpu_to_le32(lblock);
+ if (*extoffset + adsize > inode->i_sb->s_blocksize)
+ {
+ loffset = *extoffset;
+ aed->lengthAllocDescs = cpu_to_le32(adsize);
+ sptr = (*bh)->b_data + *extoffset - adsize;
+ dptr = nbh->b_data + sizeof(struct AllocExtDesc);
+ memcpy(dptr, sptr, adsize);
+ *extoffset = sizeof(struct AllocExtDesc) + adsize;
+ }
+ else
+ {
+ loffset = *extoffset + adsize;
+ aed->lengthAllocDescs = cpu_to_le32(0);
+ sptr = (*bh)->b_data + *extoffset;
+ *extoffset = sizeof(struct AllocExtDesc);
+
+ if (UDF_I_LOCATION(inode).logicalBlockNum == lblock)
+ UDF_I_LENALLOC(inode) += adsize;
+ else
+ {
+ aed = (struct AllocExtDesc *)(*bh)->b_data;
+ aed->lengthAllocDescs =
+ cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
+ }
+ }
+ udf_new_tag(nbh->b_data, TID_ALLOC_EXTENT_DESC, 2, 1,
+ bloc->logicalBlockNum, sizeof(tag));
+ switch (UDF_I_ALLOCTYPE(inode))
+ {
+ case ICB_FLAG_AD_SHORT:
+ {
+ sad = (short_ad *)sptr;
+ sad->extLength = EXTENT_NEXT_EXTENT_ALLOCDECS << 30 |
+ inode->i_sb->s_blocksize;
+ sad->extPosition = cpu_to_le32(bloc->logicalBlockNum);
+ break;
+ }
+ case ICB_FLAG_AD_LONG:
+ {
+ lad = (long_ad *)sptr;
+ lad->extLength = EXTENT_NEXT_EXTENT_ALLOCDECS << 30 |
+ inode->i_sb->s_blocksize;
+ lad->extLocation = cpu_to_lelb(*bloc);
+ break;
+ }
+ }
+ udf_update_tag((*bh)->b_data, loffset);
+ mark_buffer_dirty(*bh, 1);
+ udf_release_data(*bh);
+ *bh = nbh;
+ }
+
+ ret = udf_write_aext(inode, *bloc, extoffset, eloc, elen, bh, inc);
+
+ if (!memcmp(&UDF_I_LOCATION(inode), bloc, sizeof(lb_addr)))
+ {
+ UDF_I_LENALLOC(inode) += adsize;
+ mark_inode_dirty(inode);
+ }
+ else
+ {
+ aed = (struct AllocExtDesc *)(*bh)->b_data;
+ aed->lengthAllocDescs =
+ cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
+ udf_update_tag((*bh)->b_data, *extoffset + (inc ? 0 : adsize));
+ mark_buffer_dirty(*bh, 1);
+ }
+
+ return ret;
+}
+
+int udf_write_aext(struct inode *inode, lb_addr bloc, int *extoffset,
+ lb_addr eloc, Uint32 elen, struct buffer_head **bh, int inc)
+{
+ int adsize;
+ short_ad *sad = NULL;
+ long_ad *lad = NULL;
+
+ if (!(*bh))
+ {
+ if (!(*bh = udf_tread(inode->i_sb,
+ udf_get_lb_pblock(inode->i_sb, bloc, 0),
+ inode->i_sb->s_blocksize)))
+ {
+ udf_debug("reading block %d failed!\n",
+ udf_get_lb_pblock(inode->i_sb, bloc, 0));
+ return -1;
+ }
+ }
+
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+ adsize = sizeof(short_ad);
+ else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+ adsize = sizeof(long_ad);
+ else
+ return -1;
+
+ switch (UDF_I_ALLOCTYPE(inode))
+ {
+ case ICB_FLAG_AD_SHORT:
+ {
+ sad = (short_ad *)((*bh)->b_data + *extoffset);
+ sad->extLength = cpu_to_le32(elen);
+ sad->extPosition = cpu_to_le32(eloc.logicalBlockNum);
+ break;
+ }
+ case ICB_FLAG_AD_LONG:
+ {
+ lad = (long_ad *)((*bh)->b_data + *extoffset);
+ lad->extLength = cpu_to_le32(elen);
+ lad->extLocation = cpu_to_lelb(eloc);
+ break;
+ }
+ }
+
+ if (memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
+ {
+ struct AllocExtDesc *aed = (struct AllocExtDesc *)(*bh)->b_data;
+ udf_update_tag((*bh)->b_data,
+ le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct AllocExtDesc));
+ }
+
+ mark_buffer_dirty(*bh, 1);
+
+ if (inc)
+ *extoffset += adsize;
+ return (elen >> 30);
+}
+
+int udf_next_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
+ lb_addr *eloc, Uint32 *elen, struct buffer_head **bh, int inc)
+{
+ int pos, alen;
+ Uint8 etype;
+
+ if (!(*bh))
+ {
+ if (!(*bh = udf_tread(inode->i_sb,
+ udf_get_lb_pblock(inode->i_sb, *bloc, 0),
+ inode->i_sb->s_blocksize)))
+ {
+ udf_debug("reading block %d failed!\n",
+ udf_get_lb_pblock(inode->i_sb, *bloc, 0));
+ return -1;
+ }
+ }
+
+ if (!memcmp(&UDF_I_LOCATION(inode), bloc, sizeof(lb_addr)))
+ {
+ pos = udf_file_entry_alloc_offset(inode);
+ alen = UDF_I_LENALLOC(inode) + pos;
+ }
+ else
+ {
+ struct AllocExtDesc *aed = (struct AllocExtDesc *)(*bh)->b_data;
+
+ pos = sizeof(struct AllocExtDesc);
+ alen = le32_to_cpu(aed->lengthAllocDescs) + pos;
+ }
+
+ if (!(*extoffset))
+ *extoffset = pos;
+
+ switch (UDF_I_ALLOCTYPE(inode))
+ {
+ case ICB_FLAG_AD_SHORT:
+ {
+ short_ad *sad;
+
+ if (!(sad = udf_get_fileshortad((*bh)->b_data, alen, extoffset, inc)))
+ return -1;
+
+ if ((etype = le32_to_cpu(sad->extLength) >> 30) == EXTENT_NEXT_EXTENT_ALLOCDECS)
+ {
+ bloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
+ *extoffset = 0;
+ udf_release_data(*bh);
+ *bh = NULL;
+ return udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, inc);
+ }
+ else
+ {
+ eloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
+ eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
+ *elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK;
+ }
+ break;
+ }
+ case ICB_FLAG_AD_LONG:
+ {
+ long_ad *lad;
+
+ if (!(lad = udf_get_filelongad((*bh)->b_data, alen, extoffset, inc)))
+ return -1;
+
+ if ((etype = le32_to_cpu(lad->extLength) >> 30) == EXTENT_NEXT_EXTENT_ALLOCDECS)
+ {
+ *bloc = lelb_to_cpu(lad->extLocation);
+ *extoffset = 0;
+ udf_release_data(*bh);
+ *bh = NULL;
+ return udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, inc);
+ }
+ else
+ {
+ *eloc = lelb_to_cpu(lad->extLocation);
+ *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK;
+ }
+ break;
+ }
+ default:
+ {
+ udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode));
+ return -1;
+ }
+ }
+ if (*elen)
+ return etype;
+
+ udf_debug("Empty Extent!\n");
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+ *extoffset -= sizeof(short_ad);
+ else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+ *extoffset -= sizeof(long_ad);
+ return -1;
+}
+
+int udf_current_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
+ lb_addr *eloc, Uint32 *elen, struct buffer_head **bh, int inc)
+{
+ int pos, alen;
+ Uint8 etype;
+
+ if (!(*bh))
+ {
+ if (!(*bh = udf_tread(inode->i_sb,
+ udf_get_lb_pblock(inode->i_sb, *bloc, 0),
+ inode->i_sb->s_blocksize)))
+ {
+ udf_debug("reading block %d failed!\n",
+ udf_get_lb_pblock(inode->i_sb, *bloc, 0));
+ return -1;
+ }
+ }
+
+ if (!memcmp(&UDF_I_LOCATION(inode), bloc, sizeof(lb_addr)))
+ {
+ if (!(UDF_I_EXTENDED_FE(inode)))
+ pos = sizeof(struct FileEntry) + UDF_I_LENEATTR(inode);
+ else
+ pos = sizeof(struct ExtendedFileEntry) + UDF_I_LENEATTR(inode);
+ alen = UDF_I_LENALLOC(inode) + pos;
+ }
+ else
+ {
+ struct AllocExtDesc *aed = (struct AllocExtDesc *)(*bh)->b_data;
+
+ pos = sizeof(struct AllocExtDesc);
+ alen = le32_to_cpu(aed->lengthAllocDescs) + pos;
+ }
+
+ if (!(*extoffset))
+ *extoffset = pos;
+
+ switch (UDF_I_ALLOCTYPE(inode))
+ {
+ case ICB_FLAG_AD_SHORT:
+ {
+ short_ad *sad;
+
+ if (!(sad = udf_get_fileshortad((*bh)->b_data, alen, extoffset, inc)))
+ return -1;
+
+ etype = le32_to_cpu(sad->extLength) >> 30;
+ eloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
+ eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
+ *elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK;
+ break;
+ }
+ case ICB_FLAG_AD_LONG:
+ {
+ long_ad *lad;
+
+ if (!(lad = udf_get_filelongad((*bh)->b_data, alen, extoffset, inc)))
+ return -1;
+
+ etype = le32_to_cpu(lad->extLength) >> 30;
+ *eloc = lelb_to_cpu(lad->extLocation);
+ *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK;
+ break;
+ }
+ default:
+ {
+ udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode));
+ return -1;
+ }
+ }
+ if (*elen)
+ return etype;
+
+ udf_debug("Empty Extent!\n");
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+ *extoffset -= sizeof(short_ad);
+ else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+ *extoffset -= sizeof(long_ad);
+ return -1;
+}
+
+int udf_insert_aext(struct inode *inode, lb_addr bloc, int extoffset,
+ lb_addr neloc, Uint32 nelen, struct buffer_head *bh)
+{
+ lb_addr oeloc;
+ Uint32 oelen;
+ int type;
+
+ if (!bh)
+ {
+ if (!(bh = udf_tread(inode->i_sb,
+ udf_get_lb_pblock(inode->i_sb, bloc, 0),
+ inode->i_sb->s_blocksize)))
+ {
+ udf_debug("reading block %d failed!\n",
+ udf_get_lb_pblock(inode->i_sb, bloc, 0));
+ return -1;
+ }
+ }
+
+ while ((type = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1)
+ {
+ udf_write_aext(inode, bloc, &extoffset, neloc, nelen, &bh, 1);
+
+ neloc = oeloc;
+ nelen = (type << 30) | oelen;
+ }
+ udf_add_aext(inode, &bloc, &extoffset, neloc, nelen, &bh, 1);
+ return (nelen >> 30);
+}
+
+int udf_delete_aext(struct inode *inode, lb_addr nbloc, int nextoffset,
+ lb_addr eloc, Uint32 elen, struct buffer_head *nbh)
+{
+ struct buffer_head *obh;
+ lb_addr obloc;
+ int oextoffset, adsize;
+ char type;
+ struct AllocExtDesc *aed;
+
+ if (!(nbh))
+ {
+ if (!(nbh = udf_tread(inode->i_sb,
+ udf_get_lb_pblock(inode->i_sb, nbloc, 0),
+ inode->i_sb->s_blocksize)))
+ {
+ udf_debug("reading block %d failed!\n",
+ udf_get_lb_pblock(inode->i_sb, nbloc, 0));
+ return -1;
+ }
+ }
+ else
+ atomic_inc(&nbh->b_count);
+ atomic_inc(&nbh->b_count);
+
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+ adsize = sizeof(short_ad);
+ else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+ adsize = sizeof(long_ad);
+ else
+ adsize = 0;
+
+ obh = nbh;
+ obloc = nbloc;
+ oextoffset = nextoffset;
+
+ if (udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1) == -1)
+ return -1;
+
+ while ((type = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1)
+ {
+ udf_write_aext(inode, obloc, &oextoffset, eloc, (type << 30) | elen, &obh, 1);
+ if (memcmp(&nbloc, &obloc, sizeof(lb_addr)))
+ {
+ obloc = nbloc;
+ udf_release_data(obh);
+ atomic_inc(&nbh->b_count);
+ obh = nbh;
+ oextoffset = nextoffset - adsize;
+ }
+ }
+ memset(&eloc, 0x00, sizeof(lb_addr));
+ elen = 0;
+
+ if (memcmp(&nbloc, &obloc, sizeof(lb_addr)))
+ {
+ udf_free_blocks(inode, nbloc, 0, 1);
+ udf_write_aext(inode, obloc, &oextoffset, eloc, elen, &obh, 1);
+ udf_write_aext(inode, obloc, &oextoffset, eloc, elen, &obh, 1);
+ if (!memcmp(&UDF_I_LOCATION(inode), &obloc, sizeof(lb_addr)))
+ {
+ UDF_I_LENALLOC(inode) -= (adsize * 2);
+ mark_inode_dirty(inode);
+ }
+ else
+ {
+ aed = (struct AllocExtDesc *)(obh)->b_data;
+ aed->lengthAllocDescs =
+ cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize));
+ udf_update_tag((obh)->b_data, oextoffset - (2*adsize));
+ mark_buffer_dirty(obh, 1);
+ }
+ }
+ else
+ {
+ udf_write_aext(inode, obloc, &oextoffset, eloc, elen, &obh, 1);
+ if (!memcmp(&UDF_I_LOCATION(inode), &obloc, sizeof(lb_addr)))
+ {
+ UDF_I_LENALLOC(inode) -= adsize;
+ mark_inode_dirty(inode);
+ }
+ else
+ {
+ aed = (struct AllocExtDesc *)(obh)->b_data;
+ aed->lengthAllocDescs =
+ cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize);
+ udf_update_tag((obh)->b_data, oextoffset - adsize);
+ mark_buffer_dirty(obh, 1);
+ }
+ }
+
+ udf_release_data(nbh);
+ udf_release_data(obh);
+ return (elen >> 30);
+}
+
+int inode_bmap(struct inode *inode, int block, lb_addr *bloc, Uint32 *extoffset,
+ lb_addr *eloc, Uint32 *elen, Uint32 *offset, struct buffer_head **bh)
+{
+ int etype, lbcount = 0, b_off;
+
+ if (block < 0)
+ {
+ printk(KERN_ERR "udf: inode_bmap: block < 0\n");
+ return 0;
+ }
+ if (!inode)
+ {
+ printk(KERN_ERR "udf: inode_bmap: NULL inode\n");
+ return 0;
+ }
+
+ b_off = block << inode->i_sb->s_blocksize_bits;
+ *bloc = UDF_I_LOCATION(inode);
+ *eloc = UDF_I_EXT0LOC(inode);
+ *elen = UDF_I_EXT0LEN(inode) & UDF_EXTENT_LENGTH_MASK;
+ *extoffset = udf_file_entry_alloc_offset(inode);
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+ *extoffset += sizeof(short_ad);
+ else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+ *extoffset += sizeof(long_ad);
+ etype = UDF_I_EXT0LEN(inode) >> 30;
+
+ while (lbcount + *elen <= b_off)
+ {
+ lbcount += *elen;
+ if ((etype = udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, 1)) == -1)
+ {
+ *offset = (b_off - lbcount) >> inode->i_sb->s_blocksize_bits;
+ return -1;
+ }
+ }
+ *offset = (b_off - lbcount) >> inode->i_sb->s_blocksize_bits;
+
+ return etype;
+}
+
+long udf_locked_block_map(struct inode *inode, long block)
+{
+ lb_addr eloc, bloc;
+ Uint32 offset, extoffset, elen;
+ struct buffer_head *bh = NULL;
+ int ret;
+
+ if (inode_bmap(inode, block, &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
+ ret = udf_get_lb_pblock(inode->i_sb, eloc, offset);
+ else
+ ret = 0;
+
+ if (bh)
+ udf_release_data(bh);
+
+ if (UDF_SB(inode->i_sb)->s_flags & UDF_FLAG_VARCONV)
+ return udf_fixed_to_variable(ret);
+ else
+ return ret;
+}
+
+long udf_block_map(struct inode *inode, long block)
+{
+ int ret;
+
+ lock_kernel();
+ ret = udf_locked_block_map(inode, block);
+ unlock_kernel();
+ return ret;
+}
diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c
new file mode 100644
index 000000000..91ead3d39
--- /dev/null
+++ b/fs/udf/lowlevel.c
@@ -0,0 +1,149 @@
+/*
+ * lowlevel.c
+ *
+ * PURPOSE
+ * Low Level Device Routines for the UDF filesystem
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ *
+ * (C) 1999 Ben Fennema
+ *
+ * HISTORY
+ *
+ * 03/26/99 blf Created.
+ */
+
+#include "udfdecl.h"
+
+#include <linux/blkdev.h>
+#include <linux/cdrom.h>
+#include <asm/uaccess.h>
+#include <scsi/scsi.h>
+
+typedef struct scsi_device Scsi_Device;
+typedef struct scsi_cmnd Scsi_Cmnd;
+
+#include <scsi/scsi_ioctl.h>
+
+#include <linux/udf_fs.h>
+#include "udf_sb.h"
+
+unsigned int
+udf_get_last_session(kdev_t dev)
+{
+ struct cdrom_multisession ms_info;
+ unsigned int vol_desc_start;
+ struct inode inode_fake;
+ extern struct file_operations * get_blkfops(unsigned int);
+ int i;
+
+ vol_desc_start=0;
+ if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
+ {
+ /* Whoops. We must save the old FS, since otherwise
+ * we would destroy the kernels idea about FS on root
+ * mount in read_super... [chexum]
+ */
+ mm_segment_t old_fs=get_fs();
+ inode_fake.i_rdev=dev;
+ ms_info.addr_format=CDROM_LBA;
+ set_fs(KERNEL_DS);
+ i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
+ NULL,
+ CDROMMULTISESSION,
+ (unsigned long) &ms_info);
+ set_fs(old_fs);
+
+#define WE_OBEY_THE_WRITTEN_STANDARDS 1
+
+ if (i == 0)
+ {
+ udf_debug("XA disk: %s, vol_desc_start=%d\n",
+ (ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
+#if WE_OBEY_THE_WRITTEN_STANDARDS
+ if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
+#endif
+ vol_desc_start = ms_info.addr.lba;
+ }
+ else
+ {
+ udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i);
+ }
+ }
+ else
+ {
+ udf_debug("Device doesn't know how to ioctl?\n");
+ }
+ return vol_desc_start;
+}
+
+unsigned int
+udf_get_last_block(kdev_t dev, int *flags)
+{
+ extern int *blksize_size[];
+ struct inode inode_fake;
+ extern struct file_operations * get_blkfops(unsigned int);
+ int ret;
+ unsigned long lblock;
+ unsigned int hbsize = get_hardblocksize(dev);
+ unsigned int mult = 0;
+ unsigned int div = 0;
+
+ if (!hbsize)
+ hbsize = 512;
+
+ if (hbsize > blksize_size[MAJOR(dev)][MINOR(dev)])
+ mult = hbsize / blksize_size[MAJOR(dev)][MINOR(dev)];
+ else if (blksize_size[MAJOR(dev)][MINOR(dev)] > hbsize)
+ div = blksize_size[MAJOR(dev)][MINOR(dev)] / hbsize;
+
+ if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
+ {
+ /* Whoops. We must save the old FS, since otherwise
+ * we would destroy the kernels idea about FS on root
+ * mount in read_super... [chexum]
+ */
+ mm_segment_t old_fs=get_fs();
+ inode_fake.i_rdev=dev;
+ set_fs(KERNEL_DS);
+
+ lblock = 0;
+ ret = get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
+ NULL,
+ BLKGETSIZE,
+ (unsigned long) &lblock);
+
+ if (!ret) /* Hard Disk */
+ {
+ if (mult)
+ lblock *= mult;
+ else if (div)
+ lblock /= div;
+ }
+ else /* CDROM */
+ {
+ ret = get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
+ NULL,
+ CDROM_LAST_WRITTEN,
+ (unsigned long) &lblock);
+ }
+
+ set_fs(old_fs);
+ if (!ret)
+ return lblock - 1;
+ }
+ else
+ {
+ udf_debug("Device doesn't know how to ioctl?\n");
+ }
+ return 0;
+}
diff --git a/fs/udf/misc.c b/fs/udf/misc.c
new file mode 100644
index 000000000..2d7eb08f4
--- /dev/null
+++ b/fs/udf/misc.c
@@ -0,0 +1,540 @@
+/*
+ * misc.c
+ *
+ * PURPOSE
+ * Miscellaneous routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ *
+ * (C) 1998 Dave Boynton
+ * (C) 1998-1999 Ben Fennema
+ * (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ * 04/19/99 blf partial support for reading/writing specific EA's
+ */
+
+
+#if defined(__linux__) && defined(__KERNEL__)
+
+#include "udfdecl.h"
+
+#include "udf_sb.h"
+#include "udf_i.h"
+
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/udf_fs.h>
+
+#else
+
+#include "udfdecl.h"
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+int udf_blocksize=0;
+int udf_errno=0;
+
+void
+udf_setblocksize(int size)
+{
+ udf_blocksize=size;
+}
+#endif
+
+Uint32
+udf64_low32(Uint64 indat)
+{
+ return indat & 0x00000000FFFFFFFFULL;
+}
+
+Uint32
+udf64_high32(Uint64 indat)
+{
+ return indat >> 32;
+}
+
+/*
+ * udf_stamp_to_time
+ */
+time_t *
+udf_stamp_to_time(time_t *dest, timestamp src)
+{
+ struct ktm tm;
+
+ if ((!dest))
+ return NULL;
+
+ /* this is very rough. need to find source to mktime() */
+ tm.tm_year=(src.year) - 1900;
+ tm.tm_mon=(src.month);
+ tm.tm_mday=(src.day);
+ tm.tm_hour=src.hour;
+ tm.tm_min=src.minute;
+ tm.tm_sec=src.second;
+ *dest = udf_converttime(&tm);
+ return dest;
+}
+
+uid_t udf_convert_uid(int uidin)
+{
+ if ( uidin == -1 )
+ return 0;
+ if ( uidin > (64*1024U - 1) ) /* 16 bit UID */
+ return 0;
+ return uidin;
+}
+
+gid_t udf_convert_gid(int gidin)
+{
+ if ( gidin == -1 )
+ return 0;
+ if ( gidin > (64*1024U - 1) ) /* 16 bit GID */
+ return 0;
+ return gidin;
+}
+
+#if defined(__linux__) && defined(__KERNEL__)
+
+extern struct buffer_head *
+udf_tread(struct super_block *sb, int block, int size)
+{
+ if (UDF_SB(sb)->s_flags & UDF_FLAG_VARCONV)
+ return bread(sb->s_dev, udf_fixed_to_variable(block), size);
+ else
+ return bread(sb->s_dev, block, size);
+}
+
+extern struct GenericAttrFormat *
+udf_add_extendedattr(struct inode * inode, Uint32 size, Uint32 type,
+ Uint8 loc, struct buffer_head **bh)
+{
+ Uint8 *ea = NULL, *ad = NULL;
+ long_ad eaicb;
+ int offset;
+
+ *bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+
+ if (UDF_I_EXTENDED_FE(inode) == 0)
+ {
+ struct FileEntry *fe;
+
+ fe = (struct FileEntry *)(*bh)->b_data;
+ eaicb = fe->extendedAttrICB;
+ offset = sizeof(struct FileEntry);
+ }
+ else
+ {
+ struct ExtendedFileEntry *efe;
+
+ efe = (struct ExtendedFileEntry *)(*bh)->b_data;
+ eaicb = efe->extendedAttrICB;
+ offset = sizeof(struct ExtendedFileEntry);
+ }
+
+ ea = &(*bh)->b_data[offset];
+ if (UDF_I_LENEATTR(inode))
+ offset += UDF_I_LENEATTR(inode);
+ else
+ size += sizeof(struct ExtendedAttrHeaderDesc);
+
+ ad = &(*bh)->b_data[offset];
+ if (UDF_I_LENALLOC(inode))
+ offset += UDF_I_LENALLOC(inode);
+
+ offset = inode->i_sb->s_blocksize - offset;
+
+ /* TODO - Check for FreeEASpace */
+
+ if (loc & 0x01 && offset >= size)
+ {
+ struct ExtendedAttrHeaderDesc *eahd;
+ eahd = (struct ExtendedAttrHeaderDesc *)ea;
+
+ if (UDF_I_LENALLOC(inode))
+ {
+ memmove(&ad[size], ad, UDF_I_LENALLOC(inode));
+ UDF_I_EXT0OFFS(inode) += size;
+ }
+
+ if (UDF_I_LENEATTR(inode))
+ {
+ /* check checksum/crc */
+ if (le16_to_cpu(eahd->descTag.tagIdent) != TID_EXTENDED_ATTRE_HEADER_DESC ||
+ le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
+ {
+ udf_release_data(*bh);
+ return NULL;
+ }
+ }
+ else
+ {
+ size -= sizeof(struct ExtendedAttrHeaderDesc);
+ UDF_I_LENEATTR(inode) += sizeof(struct ExtendedAttrHeaderDesc);
+ eahd->descTag.tagIdent = cpu_to_le16(TID_EXTENDED_ATTRE_HEADER_DESC);
+ eahd->descTag.descVersion = cpu_to_le16(2);
+ eahd->descTag.tagSerialNum = cpu_to_le16(1);
+ eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
+ eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
+ eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
+ }
+
+ offset = UDF_I_LENEATTR(inode);
+ if (type < 2048)
+ {
+ if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
+ {
+ Uint32 aal = le32_to_cpu(eahd->appAttrLocation);
+ memmove(&ea[offset - aal + size],
+ &ea[aal], offset - aal);
+ offset -= aal;
+ eahd->appAttrLocation = cpu_to_le32(aal + size);
+ }
+ if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode))
+ {
+ Uint32 ial = le32_to_cpu(eahd->impAttrLocation);
+ memmove(&ea[offset - ial + size],
+ &ea[ial], offset - ial);
+ offset -= ial;
+ eahd->impAttrLocation = cpu_to_le32(ial + size);
+ }
+ }
+ else if (type < 65536)
+ {
+ if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
+ {
+ Uint32 aal = le32_to_cpu(eahd->appAttrLocation);
+ memmove(&ea[offset - aal + size],
+ &ea[aal], offset - aal);
+ offset -= aal;
+ eahd->appAttrLocation = cpu_to_le32(aal + size);
+ }
+ }
+ /* rewrite CRC + checksum of eahd */
+ UDF_I_LENEATTR(inode) += size;
+ return (struct GenericAttrFormat *)&ea[offset];
+ }
+ if (loc & 0x02)
+ {
+ }
+ udf_release_data(*bh);
+ return NULL;
+}
+
+extern struct GenericAttrFormat *
+udf_get_extendedattr(struct inode * inode, Uint32 type, Uint8 subtype,
+ struct buffer_head **bh)
+{
+ struct GenericAttrFormat *gaf;
+ Uint8 *ea = NULL;
+ long_ad eaicb;
+ Uint32 offset;
+
+ *bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+
+ if (UDF_I_EXTENDED_FE(inode) == 0)
+ {
+ struct FileEntry *fe;
+
+ fe = (struct FileEntry *)(*bh)->b_data;
+ eaicb = fe->extendedAttrICB;
+ if (UDF_I_LENEATTR(inode))
+ ea = fe->extendedAttr;
+ }
+ else
+ {
+ struct ExtendedFileEntry *efe;
+
+ efe = (struct ExtendedFileEntry *)(*bh)->b_data;
+ eaicb = efe->extendedAttrICB;
+ if (UDF_I_LENEATTR(inode))
+ ea = efe->extendedAttr;
+ }
+
+ if (UDF_I_LENEATTR(inode))
+ {
+ struct ExtendedAttrHeaderDesc *eahd;
+ eahd = (struct ExtendedAttrHeaderDesc *)ea;
+
+ /* check checksum/crc */
+ if (le16_to_cpu(eahd->descTag.tagIdent) != TID_EXTENDED_ATTRE_HEADER_DESC ||
+ le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
+ {
+ udf_release_data(*bh);
+ return NULL;
+ }
+
+ if (type < 2048)
+ offset = sizeof(struct ExtendedAttrHeaderDesc);
+ else if (type < 65536)
+ offset = le32_to_cpu(eahd->impAttrLocation);
+ else
+ offset = le32_to_cpu(eahd->appAttrLocation);
+
+ while (offset < UDF_I_LENEATTR(inode))
+ {
+ gaf = (struct GenericAttrFormat *)&ea[offset];
+ if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype)
+ return gaf;
+ else
+ offset += le32_to_cpu(gaf->attrLength);
+ }
+ }
+
+ udf_release_data(*bh);
+ if (eaicb.extLength)
+ {
+ /* TODO */
+ }
+ return NULL;
+}
+
+extern struct buffer_head *
+udf_read_untagged(struct super_block *sb, Uint32 block, Uint32 offset)
+{
+ struct buffer_head *bh = NULL;
+
+ /* Read the block */
+ bh = udf_tread(sb, block+offset, sb->s_blocksize);
+ if (!bh)
+ {
+ printk(KERN_ERR "udf: udf_read_untagged(%p,%d,%d) failed\n",
+ sb, block, offset);
+ return NULL;
+ }
+ return bh;
+}
+
+/*
+ * udf_read_tagged
+ *
+ * PURPOSE
+ * Read the first block of a tagged descriptor.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+extern struct buffer_head *
+udf_read_tagged(struct super_block *sb, Uint32 block, Uint32 location, Uint16 *ident)
+{
+ tag *tag_p;
+ struct buffer_head *bh = NULL;
+ register Uint8 checksum;
+ register int i;
+
+ /* Read the block */
+ if (block == 0xFFFFFFFF)
+ return NULL;
+
+ bh = udf_tread(sb, block, sb->s_blocksize);
+ if (!bh)
+ {
+ udf_debug("block=%d, location=%d: read failed\n", block, location);
+ return NULL;
+ }
+
+ tag_p = (tag *)(bh->b_data);
+
+ *ident = le16_to_cpu(tag_p->tagIdent);
+
+ if ( location != le32_to_cpu(tag_p->tagLocation) )
+ {
+ udf_debug("location mismatch block %d, tag %d != %d\n",
+ block, le32_to_cpu(tag_p->tagLocation), location);
+ goto error_out;
+ }
+
+ /* Verify the tag checksum */
+ checksum = 0U;
+ for (i = 0; i < 4; i++)
+ checksum += (Uint8)(bh->b_data[i]);
+ for (i = 5; i < 16; i++)
+ checksum += (Uint8)(bh->b_data[i]);
+ if (checksum != tag_p->tagChecksum) {
+ printk(KERN_ERR "udf: tag checksum failed block %d\n", block);
+ goto error_out;
+ }
+
+ /* Verify the tag version */
+ if (le16_to_cpu(tag_p->descVersion) != 0x0002U &&
+ le16_to_cpu(tag_p->descVersion) != 0x0003U)
+ {
+ udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n",
+ le16_to_cpu(tag_p->descVersion), block);
+ goto error_out;
+ }
+
+ /* Verify the descriptor CRC */
+ if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
+ le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
+ le16_to_cpu(tag_p->descCRCLength), 0))
+ {
+ return bh;
+ }
+ udf_debug("Crc failure block %d: crc = %d, crclen = %d\n",
+ block, le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
+
+error_out:
+ brelse(bh);
+ return NULL;
+}
+
+extern struct buffer_head *
+udf_read_ptagged(struct super_block *sb, lb_addr loc, Uint32 offset, Uint16 *ident)
+{
+ return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
+ loc.logicalBlockNum + offset, ident);
+}
+
+void udf_release_data(struct buffer_head *bh)
+{
+ if (bh)
+ brelse(bh);
+}
+
+#endif
+
+void udf_update_tag(char *data, int length)
+{
+ tag *tptr = (tag *)data;
+ int i;
+
+ length -= sizeof(tag);
+
+ tptr->tagChecksum = 0;
+ tptr->descCRCLength = le16_to_cpu(length);
+ tptr->descCRC = le16_to_cpu(udf_crc(data + sizeof(tag), length, 0));
+
+ for (i=0; i<16; i++)
+ if (i != 4)
+ tptr->tagChecksum += (Uint8)(data[i]);
+}
+
+void udf_new_tag(char *data, Uint16 ident, Uint16 version, Uint16 snum,
+ Uint32 loc, int length)
+{
+ tag *tptr = (tag *)data;
+ tptr->tagIdent = le16_to_cpu(ident);
+ tptr->descVersion = le16_to_cpu(version);
+ tptr->tagSerialNum = le16_to_cpu(snum);
+ tptr->tagLocation = le32_to_cpu(loc);
+ udf_update_tag(data, length);
+}
+
+#ifndef __KERNEL__
+/*
+ * udf_read_tagged_data
+ *
+ * PURPOSE
+ * Read the first block of a tagged descriptor.
+ * Usable from user-land.
+ *
+ * HISTORY
+ * 10/4/98 dgb: written
+ */
+int
+udf_read_tagged_data(char *buffer, int size, int fd, int block, int offset)
+{
+ tag *tag_p;
+ register Uint8 checksum;
+ register int i;
+ unsigned long offs;
+
+ if (!buffer)
+ {
+ udf_errno = 1;
+ return -1;
+ }
+
+ if ( !udf_blocksize )
+ {
+ udf_errno = 2;
+ return -1;
+ }
+
+ if ( size < udf_blocksize )
+ {
+ udf_errno=3;
+ return -1;
+ }
+ udf_errno=0;
+
+ offs=(long)block * udf_blocksize;
+ if ( lseek(fd, offs, SEEK_SET) != offs ) {
+ udf_errno=4;
+ return -1;
+ }
+
+ i=read(fd, buffer, udf_blocksize);
+ if ( i < udf_blocksize ) {
+ udf_errno=5;
+ return -1;
+ }
+
+ tag_p = (tag *)(buffer);
+
+ /* Verify the tag location */
+ if ((block-offset) != tag_p->tagLocation) {
+#ifdef __KERNEL__
+ printk(KERN_ERR "udf: location mismatch block %d, tag %d\n",
+ block, tag_p->tagLocation);
+#else
+ udf_errno=6;
+#endif
+ goto error_out;
+ }
+
+ /* Verify the tag checksum */
+ checksum = 0U;
+ for (i = 0; i < 4; i++)
+ checksum += (Uint8)(buffer[i]);
+ for (i = 5; i < 16; i++)
+ checksum += (Uint8)(buffer[i]);
+ if (checksum != tag_p->tagChecksum) {
+#ifdef __KERNEL__
+ printk(KERN_ERR "udf: tag checksum failed\n");
+#else
+ udf_errno=7;
+#endif
+ goto error_out;
+ }
+
+ /* Verify the tag version */
+ if (tag_p->descVersion != 0x0002U) {
+#ifdef __KERNEL__
+ printk(KERN_ERR "udf: tag version 0x%04x != 0x0002U\n",
+ tag_p->descVersion);
+#else
+ udf_errno=8;
+#endif
+ goto error_out;
+ }
+
+ /* Verify the descriptor CRC */
+ if (tag_p->descCRC == udf_crc(buffer + 16, tag_p->descCRCLength, 0)) {
+ udf_errno=0;
+ return 0;
+ }
+#ifdef __KERNEL__
+ printk(KERN_ERR "udf: crc failure in udf_read_tagged\n");
+#else
+ udf_errno=9;
+#endif
+
+error_out:
+ return -1;
+}
+#endif
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
new file mode 100644
index 000000000..01b3979c9
--- /dev/null
+++ b/fs/udf/namei.c
@@ -0,0 +1,1302 @@
+/*
+ * namei.c
+ *
+ * PURPOSE
+ * Inode name handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ *
+ * (C) 1998-1999 Ben Fennema
+ * (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ * 12/12/98 blf Created. Split out the lookup code from dir.c
+ * 04/19/99 blf link, mknod, symlink support
+ *
+ */
+
+#if defined(__linux__) && defined(__KERNEL__)
+#include <linux/version.h>
+#include "udf_i.h"
+#include "udf_sb.h"
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/udf_fs.h>
+#endif
+
+#include "udfdecl.h"
+
+static inline int udf_match(int len, const char * const name, struct qstr *qs)
+{
+ if (len != qs->len)
+ return 0;
+ return !memcmp(name, qs->name, len);
+}
+
+int udf_write_fi(struct FileIdentDesc *cfi, struct FileIdentDesc *sfi,
+ struct udf_fileident_bh *fibh,
+ Uint8 *impuse, Uint8 *fileident)
+{
+ struct FileIdentDesc *efi;
+ Uint16 crclen = fibh->eoffset - fibh->soffset - sizeof(tag);
+ Uint16 crc;
+ Uint8 checksum = 0;
+ int i;
+ int offset, len;
+ int padlen = fibh->eoffset - fibh->soffset - cfi->lengthOfImpUse - cfi->lengthFileIdent -
+ sizeof(struct FileIdentDesc);
+
+ crc = udf_crc((Uint8 *)cfi + sizeof(tag), sizeof(struct FileIdentDesc) -
+ sizeof(tag), 0);
+ efi = (struct FileIdentDesc *)(fibh->ebh->b_data + fibh->soffset);
+ if (fibh->sbh == fibh->ebh ||
+ (!fileident &&
+ (sizeof(struct FileIdentDesc) + (impuse ? cfi->lengthOfImpUse : 0))
+ <= -fibh->soffset))
+ {
+ memcpy((Uint8 *)sfi, (Uint8 *)cfi, sizeof(struct FileIdentDesc));
+
+ if (impuse)
+ memcpy(sfi->impUse, impuse, cfi->lengthOfImpUse);
+
+ if (fileident)
+ memcpy(sfi->fileIdent + cfi->lengthOfImpUse, fileident,
+ cfi->lengthFileIdent);
+
+ /* Zero padding */
+ memset(sfi->fileIdent + cfi->lengthOfImpUse + cfi->lengthFileIdent, 0,
+ padlen);
+
+ if (fibh->sbh == fibh->ebh)
+ crc = udf_crc((Uint8 *)sfi + sizeof(tag), crclen, 0);
+ else
+ {
+ crc = udf_crc((Uint8 *)sfi + sizeof(tag), crclen - fibh->eoffset, 0);
+ crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
+ }
+
+ sfi->descTag.descCRC = cpu_to_le32(crc);
+ sfi->descTag.descCRCLength = cpu_to_le16(crclen);
+
+ for (i=0; i<16; i++)
+ if (i != 4)
+ checksum += ((Uint8 *)&sfi->descTag)[i];
+
+ sfi->descTag.tagChecksum = checksum;
+
+ mark_buffer_dirty(fibh->sbh, 1);
+ }
+ else
+ {
+ offset = -fibh->soffset;
+ len = sizeof(struct FileIdentDesc);
+
+ if (len <= offset)
+ memcpy((Uint8 *)sfi, (Uint8 *)cfi, len);
+ else
+ {
+ memcpy((Uint8 *)sfi, (Uint8 *)cfi, offset);
+ memcpy(fibh->ebh->b_data, (Uint8 *)cfi + offset, len - offset);
+ }
+
+ offset -= len;
+ len = cfi->lengthOfImpUse;
+
+ if (impuse)
+ {
+ if (offset <= 0)
+ memcpy(efi->impUse, impuse, len);
+ else if (sizeof(struct FileIdentDesc) + len <= -fibh->soffset)
+ memcpy(sfi->impUse, impuse, len);
+ else
+ {
+ memcpy(sfi->impUse, impuse, offset);
+ memcpy(efi->impUse + offset, impuse + offset, len - offset);
+ }
+ }
+
+ offset -= len;
+ len = cfi->lengthFileIdent;
+
+ if (fileident)
+ {
+ if (offset <= 0)
+ memcpy(efi->fileIdent + cfi->lengthOfImpUse, fileident, len);
+ else
+ {
+ memcpy(sfi->fileIdent + cfi->lengthOfImpUse, fileident, offset);
+ memcpy(efi->fileIdent + cfi->lengthOfImpUse + offset,
+ fileident + offset, len - offset);
+ }
+ }
+
+ /* Zero padding */
+ memset(efi->fileIdent + cfi->lengthOfImpUse + cfi->lengthFileIdent, 0x00,
+ padlen);
+
+ if (sizeof(tag) < -fibh->soffset)
+ {
+ crc = udf_crc((Uint8 *)sfi + sizeof(tag), crclen - fibh->eoffset, 0);
+ crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
+ }
+ else
+ crc = udf_crc((Uint8 *)fibh->ebh->b_data + fibh->eoffset - crclen, crclen, 0);
+
+ if (&(efi->descTag.descCRC) < (Uint16 *)fibh->ebh->b_data)
+ {
+ sfi->descTag.descCRC = cpu_to_le16(crc);
+ sfi->descTag.descCRCLength = cpu_to_le16(crclen);
+ }
+ else
+ {
+ efi->descTag.descCRC = cpu_to_le16(crc);
+ efi->descTag.descCRCLength = cpu_to_le16(crclen);
+ }
+
+ for (i=0; i<16; i++)
+ {
+ if (i != 4)
+ {
+ if (&(((Uint8 *)&efi->descTag)[i]) < (Uint8 *)fibh->ebh->b_data)
+ checksum += ((Uint8 *)&sfi->descTag)[i];
+ else
+ checksum += ((Uint8 *)&efi->descTag)[i];
+ }
+ }
+
+ if (&(cfi->descTag.tagChecksum) < (Uint8 *)fibh->ebh->b_data)
+ sfi->descTag.tagChecksum = checksum;
+ else
+ efi->descTag.tagChecksum = checksum;
+
+ mark_buffer_dirty(fibh->sbh, 1);
+ mark_buffer_dirty(fibh->ebh, 1);
+ }
+ return 0;
+}
+
+static struct FileIdentDesc *
+udf_find_entry(struct inode *dir, struct dentry *dentry,
+ struct udf_fileident_bh *fibh,
+ struct FileIdentDesc *cfi)
+{
+ struct FileIdentDesc *fi=NULL;
+ int f_pos, block;
+ int flen;
+ char fname[255];
+ char *nameptr;
+ Uint8 lfi;
+ Uint16 liu;
+ int size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2;
+ lb_addr bloc, eloc;
+ Uint32 extoffset, elen, offset;
+ struct buffer_head *bh = NULL;
+
+ if (!dir)
+ return NULL;
+
+ f_pos = (UDF_I_EXT0OFFS(dir) >> 2);
+
+ fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
+ if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+ &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
+ {
+ block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
+ if (++offset < (elen >> dir->i_sb->s_blocksize_bits))
+ {
+ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
+ extoffset -= sizeof(short_ad);
+ else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG)
+ extoffset -= sizeof(long_ad);
+ }
+ else
+ offset = 0;
+ }
+ else
+ {
+ udf_release_data(bh);
+ return NULL;
+ }
+
+ if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+ {
+ udf_debug("udf_tread failed: block=%d\n", block);
+ udf_release_data(bh);
+ return NULL;
+ }
+
+ while ( (f_pos < size) )
+ {
+ fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &offset, &bh);
+ liu = le16_to_cpu(cfi->lengthOfImpUse);
+ lfi = cfi->lengthFileIdent;
+
+ if (!fi)
+ {
+ if (fibh->sbh != fibh->ebh)
+ udf_release_data(fibh->ebh);
+ udf_release_data(fibh->sbh);
+ udf_release_data(bh);
+ return NULL;
+ }
+
+ if (fibh->sbh == fibh->ebh)
+ {
+ nameptr = fi->fileIdent + liu;
+ }
+ else
+ {
+ int poffset; /* Unpaded ending offset */
+
+ poffset = fibh->soffset + sizeof(struct FileIdentDesc) + liu + lfi;
+
+ if (poffset >= lfi)
+ nameptr = (Uint8 *)(fibh->ebh->b_data + poffset - lfi);
+ else
+ {
+ nameptr = fname;
+ memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
+ memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
+ }
+ }
+
+ if ( (cfi->fileCharacteristics & FILE_DELETED) != 0 )
+ {
+ if ( !IS_UNDELETE(dir->i_sb) )
+ continue;
+ }
+
+ if ( (cfi->fileCharacteristics & FILE_HIDDEN) != 0 )
+ {
+ if ( !IS_UNHIDE(dir->i_sb) )
+ continue;
+ }
+
+ if (!lfi)
+ continue;
+
+ if ((flen = udf_get_filename(nameptr, fname, lfi)))
+ {
+ if (udf_match(flen, fname, &(dentry->d_name)))
+ {
+ udf_release_data(bh);
+ return fi;
+ }
+ }
+ }
+ if (fibh->sbh != fibh->ebh)
+ udf_release_data(fibh->ebh);
+ udf_release_data(fibh->sbh);
+ udf_release_data(bh);
+ return NULL;
+}
+
+/*
+ * udf_lookup
+ *
+ * PURPOSE
+ * Look-up the inode for a given name.
+ *
+ * DESCRIPTION
+ * Required - lookup_dentry() will return -ENOTDIR if this routine is not
+ * available for a directory. The filesystem is useless if this routine is
+ * not available for at least the filesystem's root directory.
+ *
+ * This routine is passed an incomplete dentry - it must be completed by
+ * calling d_add(dentry, inode). If the name does not exist, then the
+ * specified inode must be set to null. An error should only be returned
+ * when the lookup fails for a reason other than the name not existing.
+ * Note that the directory inode semaphore is held during the call.
+ *
+ * Refer to lookup_dentry() in fs/namei.c
+ * lookup_dentry() -> lookup() -> real_lookup() -> .
+ *
+ * PRE-CONDITIONS
+ * dir Pointer to inode of parent directory.
+ * dentry Pointer to dentry to complete.
+ *
+ * POST-CONDITIONS
+ * <return> Zero on success.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+
+struct dentry *
+udf_lookup(struct inode *dir, struct dentry *dentry)
+{
+ struct inode *inode = NULL;
+ struct FileIdentDesc cfi, *fi;
+ struct udf_fileident_bh fibh;
+
+#ifdef UDF_RECOVERY
+ /* temporary shorthand for specifying files by inode number */
+ if (!strncmp(dentry->d_name.name, ".B=", 3) )
+ {
+ lb_addr lb = { 0, simple_strtoul(dentry->d_name.name+3, NULL, 0) };
+ inode = udf_iget(dir->i_sb, lb);
+ if (!inode)
+ return ERR_PTR(-EACCES);
+ }
+ else
+#endif /* UDF_RECOVERY */
+
+ if ((fi = udf_find_entry(dir, dentry, &fibh, &cfi)))
+ {
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+
+ inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));
+ if ( !inode )
+ return ERR_PTR(-EACCES);
+ }
+ d_add(dentry, inode);
+ return NULL;
+}
+
+static struct FileIdentDesc *
+udf_add_entry(struct inode *dir, struct dentry *dentry,
+ struct udf_fileident_bh *fibh,
+ struct FileIdentDesc *cfi, int *err)
+{
+ struct super_block *sb;
+ struct FileIdentDesc *fi=NULL;
+ struct ustr unifilename;
+ char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
+ int namelen;
+ int f_pos;
+ int flen;
+ char *nameptr;
+ int size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2;
+ int nfidlen;
+ Uint8 lfi;
+ Uint16 liu;
+ int block;
+ lb_addr bloc, eloc;
+ Uint32 extoffset, elen, offset;
+ struct buffer_head *bh = NULL;
+
+ *err = -EINVAL;
+ if (!dir || !dir->i_nlink)
+ return NULL;
+ sb = dir->i_sb;
+
+ if (!dentry->d_name.len)
+ return NULL;
+
+ if (dir->i_size == 0)
+ {
+ *err = -ENOENT;
+ return NULL;
+ }
+
+ if ( !(udf_char_to_ustr(&unifilename, dentry->d_name.name, dentry->d_name.len)) )
+ {
+ *err = -ENAMETOOLONG;
+ return NULL;
+ }
+
+ if ( !(namelen = udf_UTF8toCS0(name, &unifilename, UDF_NAME_LEN)) )
+ return 0;
+
+ nfidlen = (sizeof(struct FileIdentDesc) + 0 + namelen + 3) & ~3;
+
+ f_pos = (UDF_I_EXT0OFFS(dir) >> 2);
+
+ fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
+ if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+ &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
+ {
+ block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
+ if (++offset < (elen >> dir->i_sb->s_blocksize_bits))
+ {
+ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
+ extoffset -= sizeof(short_ad);
+ else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG)
+ extoffset -= sizeof(long_ad);
+ }
+ else
+ offset = 0;
+ }
+ else
+ {
+ udf_release_data(bh);
+ return NULL;
+ }
+
+ if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+ return NULL;
+
+ block = UDF_I_LOCATION(dir).logicalBlockNum;
+
+ while ( (f_pos < size) )
+ {
+ fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &offset, &bh);
+ liu = le16_to_cpu(cfi->lengthOfImpUse);
+ lfi = cfi->lengthFileIdent;
+
+ if (!fi)
+ {
+ if (fibh->sbh != fibh->ebh)
+ udf_release_data(fibh->ebh);
+ udf_release_data(fibh->sbh);
+ udf_release_data(bh);
+ return NULL;
+ }
+
+ if (fibh->sbh == fibh->ebh)
+ nameptr = fi->fileIdent + liu;
+ else
+ {
+ int poffset; /* Unpaded ending offset */
+
+ poffset = fibh->soffset + sizeof(struct FileIdentDesc) + liu + lfi;
+
+ if (poffset >= lfi)
+ nameptr = (char *)(fibh->ebh->b_data + poffset - lfi);
+ else
+ {
+ nameptr = fname;
+ memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
+ memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
+ }
+ }
+
+ if ( (cfi->fileCharacteristics & FILE_DELETED) != 0 )
+ {
+ if (((sizeof(struct FileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen)
+ {
+ udf_release_data(bh);
+ cfi->descTag.tagSerialNum = cpu_to_le16(1);
+ cfi->fileVersionNum = cpu_to_le16(1);
+ cfi->fileCharacteristics = 0;
+ cfi->lengthFileIdent = namelen;
+ cfi->lengthOfImpUse = cpu_to_le16(0);
+ if (!udf_write_fi(cfi, fi, fibh, NULL, name))
+ return fi;
+ else
+ return NULL;
+ }
+ }
+
+ if (!lfi)
+ continue;
+
+ if ((flen = udf_get_filename(nameptr, fname, lfi)))
+ {
+ if (udf_match(flen, fname, &(dentry->d_name)))
+ {
+ if (fibh->sbh != fibh->ebh)
+ udf_release_data(fibh->ebh);
+ udf_release_data(fibh->sbh);
+ udf_release_data(bh);
+ *err = -EEXIST;
+ return NULL;
+ }
+ }
+ }
+
+ f_pos += nfidlen;
+
+ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB &&
+ sb->s_blocksize - fibh->eoffset < nfidlen)
+ {
+ udf_release_data(bh);
+ bh = NULL;
+ fibh->soffset -= UDF_I_EXT0OFFS(dir);
+ fibh->eoffset -= UDF_I_EXT0OFFS(dir);
+ f_pos -= (UDF_I_EXT0OFFS(dir) >> 2);
+ udf_release_data(fibh->sbh);
+ if (!(fibh->sbh = fibh->ebh = udf_expand_adinicb(dir, &block, 1, err)))
+ return NULL;
+ bloc = UDF_I_LOCATION(dir);
+ extoffset = udf_file_entry_alloc_offset(dir);
+ }
+ else
+ {
+ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
+ extoffset -= sizeof(short_ad);
+ else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG)
+ extoffset -= sizeof(long_ad);
+ }
+
+ dir->i_size += nfidlen;
+ if (sb->s_blocksize - fibh->eoffset >= nfidlen)
+ {
+ fibh->soffset = fibh->eoffset;
+ fibh->eoffset += nfidlen;
+ if (fibh->sbh != fibh->ebh)
+ {
+ udf_release_data(fibh->sbh);
+ fibh->sbh = fibh->ebh;
+ }
+
+ if (UDF_I_ALLOCTYPE(dir) != ICB_FLAG_AD_IN_ICB)
+ {
+ Uint32 lextoffset = extoffset;
+ if (udf_next_aext(dir, &bloc, &extoffset, &eloc, &elen, &bh, 1) !=
+ EXTENT_RECORDED_ALLOCATED)
+ {
+ udf_release_data(bh);
+ udf_release_data(fibh->sbh);
+ return NULL;
+ }
+ else
+ {
+ elen += nfidlen;
+ elen = (EXTENT_RECORDED_ALLOCATED << 30) | elen;
+ udf_write_aext(dir, bloc, &lextoffset, eloc, elen, &bh, 1);
+ block = eloc.logicalBlockNum + (elen >> dir->i_sb->s_blocksize_bits);
+ }
+ }
+ else
+ block = UDF_I_LOCATION(dir).logicalBlockNum;
+
+ fi = (struct FileIdentDesc *)(fibh->sbh->b_data + fibh->soffset);
+ }
+ else
+ {
+ Uint32 lextoffset = extoffset;
+
+ fibh->soffset = fibh->eoffset - sb->s_blocksize;
+ fibh->eoffset += nfidlen - sb->s_blocksize;
+ if (fibh->sbh != fibh->ebh)
+ {
+ udf_release_data(fibh->sbh);
+ fibh->sbh = fibh->ebh;
+ }
+
+ if (udf_next_aext(dir, &bloc, &extoffset, &eloc, &elen, &bh, 1) !=
+ EXTENT_RECORDED_ALLOCATED)
+ {
+ udf_release_data(bh);
+ udf_release_data(fibh->sbh);
+ return NULL;
+ }
+ else
+ block = eloc.logicalBlockNum + (elen >> dir->i_sb->s_blocksize_bits);
+
+ *err = -ENOSPC;
+ if (!(fibh->ebh = udf_getblk(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err)))
+ {
+ udf_release_data(bh);
+ udf_release_data(fibh->sbh);
+ return NULL;
+ }
+ if (!(fibh->soffset))
+ {
+ if (udf_next_aext(dir, &bloc, &lextoffset, &eloc, &elen, &bh, 1) ==
+ EXTENT_RECORDED_ALLOCATED)
+ {
+ block = eloc.logicalBlockNum + (elen >> dir->i_sb->s_blocksize_bits);
+ }
+ else
+ block ++;
+ }
+
+ fi = (struct FileIdentDesc *)(fibh->sbh->b_data + sb->s_blocksize + fibh->soffset);
+ }
+
+ memset(cfi, 0, sizeof(struct FileIdentDesc));
+ udf_new_tag((char *)cfi, TID_FILE_IDENT_DESC, 2, 1, block, sizeof(tag));
+ cfi->fileVersionNum = cpu_to_le16(1);
+ cfi->lengthFileIdent = namelen;
+ cfi->lengthOfImpUse = cpu_to_le16(0);
+ if (!udf_write_fi(cfi, fi, fibh, NULL, name))
+ {
+ udf_release_data(bh);
+ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
+ UDF_I_LENALLOC(dir) += nfidlen;
+ dir->i_version = ++event;
+ mark_inode_dirty(dir);
+ return fi;
+ }
+ else
+ {
+ udf_release_data(bh);
+ dir->i_size -= nfidlen;
+ if (fibh->sbh != fibh->ebh)
+ udf_release_data(fibh->ebh);
+ udf_release_data(fibh->sbh);
+ return NULL;
+ }
+}
+
+static int udf_delete_entry(struct FileIdentDesc *fi,
+ struct udf_fileident_bh *fibh,
+ struct FileIdentDesc *cfi)
+{
+ cfi->fileCharacteristics |= FILE_DELETED;
+ return udf_write_fi(cfi, fi, fibh, NULL, NULL);
+}
+
+int udf_create(struct inode *dir, struct dentry *dentry, int mode)
+{
+ struct udf_fileident_bh fibh;
+ struct inode *inode;
+ struct FileIdentDesc cfi, *fi;
+ int err;
+
+ inode = udf_new_inode(dir, mode, &err);
+ if (!inode)
+ return err;
+
+ inode->i_op = &udf_file_inode_operations;
+ inode->i_mode = mode;
+ mark_inode_dirty(inode);
+
+ if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
+ {
+ udf_debug("udf_add_entry failure!\n");
+ inode->i_nlink --;
+ mark_inode_dirty(inode);
+ iput(inode);
+ return err;
+ }
+ cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+ cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
+ *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
+ cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
+ udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
+ {
+ mark_inode_dirty(dir);
+ dir->i_version = ++event;
+ }
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+ d_instantiate(dentry, inode);
+ return 0;
+}
+
+int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
+{
+ struct inode * inode;
+ struct udf_fileident_bh fibh;
+ int err;
+ struct FileIdentDesc cfi, *fi;
+
+ err = -EIO;
+ inode = udf_new_inode(dir, mode, &err);
+ if (!inode)
+ goto out;
+
+ inode->i_uid = current->fsuid;
+ inode->i_mode = mode;
+ inode->i_op = NULL;
+ if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
+ {
+ udf_debug("udf_add_entry failure!\n");
+ inode->i_nlink --;
+ mark_inode_dirty(inode);
+ iput(inode);
+ return err;
+ }
+ cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+ cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
+ *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
+ cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
+ udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
+ {
+ mark_inode_dirty(dir);
+ dir->i_version = ++event;
+ }
+ if (S_ISREG(inode->i_mode))
+ {
+ inode->i_op = &udf_file_inode_operations;
+ }
+ else if (S_ISCHR(inode->i_mode))
+ {
+ inode->i_op = &chrdev_inode_operations;
+ }
+ else if (S_ISBLK(inode->i_mode))
+ {
+ inode->i_op = &blkdev_inode_operations;
+ }
+ else if (S_ISFIFO(inode->i_mode))
+ {
+ init_fifo(inode);
+ }
+ if (S_ISBLK(mode) || S_ISCHR(mode))
+ inode->i_rdev = to_kdev_t(rdev);
+ mark_inode_dirty(inode);
+
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+ d_instantiate(dentry, inode);
+ err = 0;
+out:
+ return err;
+}
+
+int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+{
+ struct inode * inode;
+ struct udf_fileident_bh fibh;
+ int err;
+ struct FileEntry *fe;
+ struct FileIdentDesc cfi, *fi;
+ Uint32 loc;
+
+ err = -EMLINK;
+ if (dir->i_nlink >= (256<<sizeof(dir->i_nlink))-1)
+ goto out;
+
+ err = -EIO;
+ inode = udf_new_inode(dir, S_IFDIR, &err);
+ if (!inode)
+ goto out;
+
+ inode->i_op = &udf_dir_inode_operations;
+ inode->i_size = (sizeof(struct FileIdentDesc) + 3) & ~3;
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+ {
+ UDF_I_EXT0LEN(inode) = inode->i_size;
+ UDF_I_EXT0LOC(inode) = UDF_I_LOCATION(inode);
+ UDF_I_LENALLOC(inode) = inode->i_size;
+ loc = UDF_I_LOCATION(inode).logicalBlockNum;
+ fibh.sbh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+ }
+ else
+ {
+ fibh.sbh = udf_bread (inode, 0, 1, &err);
+ loc = UDF_I_EXT0LOC(inode).logicalBlockNum;
+ }
+
+ if (!fibh.sbh)
+ {
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ iput(inode);
+ goto out;
+ }
+ inode->i_nlink = 2;
+ fe = (struct FileEntry *)fibh.sbh->b_data;
+ fi = (struct FileIdentDesc *)&(fe->extendedAttr[UDF_I_LENEATTR(inode)]);
+ udf_new_tag((char *)&cfi, TID_FILE_IDENT_DESC, 2, 1, loc,
+ sizeof(struct FileIdentDesc));
+ cfi.fileVersionNum = cpu_to_le16(1);
+ cfi.fileCharacteristics = FILE_DIRECTORY | FILE_PARENT;
+ cfi.lengthFileIdent = 0;
+ cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+ cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(dir));
+ *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
+ cpu_to_le32(UDF_I_UNIQUE(dir) & 0x00000000FFFFFFFFUL);
+ cfi.lengthOfImpUse = cpu_to_le16(0);
+ fibh.ebh = fibh.sbh;
+ fibh.soffset = sizeof(struct FileEntry);
+ fibh.eoffset = sizeof(struct FileEntry) + inode->i_size;
+ udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+ udf_release_data(fibh.sbh);
+ inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask);
+ if (dir->i_mode & S_ISGID)
+ inode->i_mode |= S_ISGID;
+ mark_inode_dirty(inode);
+
+ if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
+ {
+ udf_debug("udf_add_entry failure!\n");
+ inode->i_nlink = 0;
+ mark_inode_dirty(inode);
+ iput(inode);
+ goto out;
+ }
+ cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+ cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
+ *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
+ cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
+ cfi.fileCharacteristics |= FILE_DIRECTORY;
+ udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+ dir->i_version = ++event;
+ dir->i_nlink++;
+ mark_inode_dirty(dir);
+ d_instantiate(dentry, inode);
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+ err = 0;
+out:
+ return err;
+}
+
+static int empty_dir(struct inode *dir)
+{
+ struct FileIdentDesc *fi, cfi;
+ struct udf_fileident_bh fibh;
+ int f_pos;
+ int size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2;
+ int block;
+ lb_addr bloc, eloc;
+ Uint32 extoffset, elen, offset;
+ struct buffer_head *bh = NULL;
+
+ f_pos = (UDF_I_EXT0OFFS(dir) >> 2);
+
+ fibh.soffset = fibh.eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
+ if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+ &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
+ {
+ block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
+ if (++offset < (elen >> dir->i_sb->s_blocksize_bits))
+ {
+ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
+ extoffset -= sizeof(short_ad);
+ else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG)
+ extoffset -= sizeof(long_ad);
+ }
+ else
+ offset = 0;
+ }
+ else
+ {
+ udf_release_data(bh);
+ return 0;
+ }
+
+ if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+ return 0;
+
+ while ( (f_pos < size) )
+ {
+ fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &bloc, &extoffset, &offset, &bh);
+
+ if (!fi)
+ {
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+ udf_release_data(bh);
+ return 0;
+ }
+
+ if (cfi.lengthFileIdent && (cfi.fileCharacteristics & FILE_DELETED) == 0)
+ {
+ udf_release_data(bh);
+ return 0;
+ }
+ }
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+ udf_release_data(bh);
+ return 1;
+}
+
+int udf_rmdir(struct inode * dir, struct dentry * dentry)
+{
+ int retval;
+ struct inode * inode;
+ struct udf_fileident_bh fibh;
+ struct FileIdentDesc *fi, cfi;
+
+ retval = -ENOENT;
+ fi = udf_find_entry(dir, dentry, &fibh, &cfi);
+ if (!fi)
+ goto out;
+
+ inode = dentry->d_inode;
+
+ retval = -EIO;
+ if (udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0) != inode->i_ino)
+ goto end_rmdir;
+ retval = -ENOTEMPTY;
+ if (!empty_dir(inode))
+ goto end_rmdir;
+ retval = udf_delete_entry(fi, &fibh, &cfi);
+ dir->i_version = ++event;
+ if (retval)
+ goto end_rmdir;
+ if (inode->i_nlink != 2)
+ udf_warning(inode->i_sb, "udf_rmdir",
+ "empty directory has nlink != 2 (%d)",
+ inode->i_nlink);
+ inode->i_version = ++event;
+ inode->i_nlink = 0;
+ inode->i_size = 0;
+ mark_inode_dirty(inode);
+ dir->i_nlink --;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ UDF_I_UCTIME(inode) = UDF_I_UCTIME(dir) = UDF_I_UMTIME(dir) = CURRENT_UTIME;
+ mark_inode_dirty(dir);
+ d_delete(dentry);
+
+end_rmdir:
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+out:
+ return retval;
+}
+
+int udf_unlink(struct inode * dir, struct dentry * dentry)
+{
+ int retval;
+ struct inode * inode;
+ struct udf_fileident_bh fibh;
+ struct FileIdentDesc *fi;
+ struct FileIdentDesc cfi;
+
+ retval = -ENOENT;
+ fi = udf_find_entry(dir, dentry, &fibh, &cfi);
+ if (!fi)
+ goto out;
+
+ inode = dentry->d_inode;
+
+ retval = -EIO;
+
+ if (udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0) !=
+ inode->i_ino)
+ {
+ goto end_unlink;
+ }
+
+ if (!inode->i_nlink)
+ {
+ udf_debug("Deleting nonexistent file (%lu), %d\n",
+ inode->i_ino, inode->i_nlink);
+ inode->i_nlink = 1;
+ }
+ retval = udf_delete_entry(fi, &fibh, &cfi);
+ if (retval)
+ goto end_unlink;
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ UDF_I_UCTIME(dir) = UDF_I_UMTIME(dir) = CURRENT_UTIME;
+ mark_inode_dirty(dir);
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ inode->i_ctime = dir->i_ctime;
+ retval = 0;
+ d_delete(dentry); /* This also frees the inode */
+
+end_unlink:
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+out:
+ return retval;
+}
+
+int udf_symlink(struct inode * dir, struct dentry * dentry, const char * symname)
+{
+ struct inode * inode;
+ struct PathComponent *pc;
+ struct udf_fileident_bh fibh;
+ struct buffer_head *bh = NULL;
+ int eoffset, elen = 0;
+ struct FileIdentDesc *fi;
+ struct FileIdentDesc cfi;
+ char *ea;
+ int err;
+
+ if (!(inode = udf_new_inode(dir, S_IFLNK, &err)))
+ goto out;
+
+ inode->i_mode = S_IFLNK | S_IRWXUGO;
+ inode->i_op = &udf_symlink_inode_operations;
+
+ bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+ ea = bh->b_data + udf_file_entry_alloc_offset(inode);
+
+ eoffset = inode->i_sb->s_blocksize - (ea - bh->b_data);
+ pc = (struct PathComponent *)ea;
+
+ if (*symname == '/')
+ {
+ do
+ {
+ symname++;
+ } while (*symname == '/');
+
+ pc->componentType = 1;
+ pc->lengthComponentIdent = 0;
+ pc->componentFileVersionNum = 0;
+ pc += sizeof(struct PathComponent);
+ elen += sizeof(struct PathComponent);
+ }
+
+ while (*symname && eoffset > elen + sizeof(struct PathComponent))
+ {
+ char *compstart;
+ pc = (struct PathComponent *)(ea + elen);
+
+ compstart = (char *)symname;
+
+ do
+ {
+ symname++;
+ } while (*symname && *symname != '/');
+
+ pc->componentType = 5;
+ pc->lengthComponentIdent = 0;
+ pc->componentFileVersionNum = 0;
+ if (pc->componentIdent[0] == '.')
+ {
+ if (pc->lengthComponentIdent == 1)
+ pc->componentType = 4;
+ else if (pc->lengthComponentIdent == 2 && pc->componentIdent[1] == '.')
+ pc->componentType = 3;
+ }
+
+ if (pc->componentType == 5)
+ {
+ if (elen + sizeof(struct PathComponent) + symname - compstart > eoffset)
+ pc->lengthComponentIdent = eoffset - elen - sizeof(struct PathComponent);
+ else
+ pc->lengthComponentIdent = symname - compstart;
+
+ memcpy(pc->componentIdent, compstart, pc->lengthComponentIdent);
+ }
+
+ elen += sizeof(struct PathComponent) + pc->lengthComponentIdent;
+
+ if (*symname)
+ {
+ do
+ {
+ symname++;
+ } while (*symname == '/');
+ }
+ }
+
+ udf_release_data(bh);
+ UDF_I_LENALLOC(inode) = inode->i_size = elen;
+ mark_inode_dirty(inode);
+
+ if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
+ goto out;
+ cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+ cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
+ if (UDF_SB_LVIDBH(inode->i_sb))
+ {
+ struct LogicalVolHeaderDesc *lvhd;
+ Uint64 uniqueID;
+ lvhd = (struct LogicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
+ uniqueID = le64_to_cpu(lvhd->uniqueID);
+ *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
+ le32_to_cpu(uniqueID & 0x00000000FFFFFFFFUL);
+ if (!(++uniqueID & 0x00000000FFFFFFFFUL))
+ uniqueID += 16;
+ lvhd->uniqueID = cpu_to_le64(uniqueID);
+ mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb), 1);
+ }
+ udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
+ {
+ mark_inode_dirty(dir);
+ dir->i_version = ++event;
+ }
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+ d_instantiate(dentry, inode);
+ err = 0;
+
+out:
+ return err;
+}
+
+int udf_link(struct dentry * old_dentry, struct inode * dir,
+ struct dentry *dentry)
+{
+ struct inode *inode = old_dentry->d_inode;
+ struct udf_fileident_bh fibh;
+ int err;
+ struct FileIdentDesc cfi, *fi;
+
+ if (S_ISDIR(inode->i_mode))
+ return -EPERM;
+
+ if (inode->i_nlink >= (256<<sizeof(inode->i_nlink))-1)
+ return -EMLINK;
+
+ if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
+ return err;
+ cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+ cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
+ if (UDF_SB_LVIDBH(inode->i_sb))
+ {
+ struct LogicalVolHeaderDesc *lvhd;
+ Uint64 uniqueID;
+ lvhd = (struct LogicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
+ uniqueID = le64_to_cpu(lvhd->uniqueID);
+ *(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
+ cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
+ if (!(++uniqueID & 0x00000000FFFFFFFFUL))
+ uniqueID += 16;
+ lvhd->uniqueID = cpu_to_le64(uniqueID);
+ mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb), 1);
+ }
+ udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+ if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
+ {
+ mark_inode_dirty(dir);
+ dir->i_version = ++event;
+ }
+ if (fibh.sbh != fibh.ebh)
+ udf_release_data(fibh.ebh);
+ udf_release_data(fibh.sbh);
+ inode->i_nlink ++;
+ inode->i_ctime = CURRENT_TIME;
+ UDF_I_UCTIME(inode) = CURRENT_UTIME;
+ mark_inode_dirty(inode);
+ inode->i_count ++;
+ d_instantiate(dentry, inode);
+ return 0;
+}
+
+/* Anybody can rename anything with this: the permission checks are left to the
+ * higher-level routines.
+ */
+int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
+ struct inode * new_dir, struct dentry * new_dentry)
+{
+ struct inode * old_inode, * new_inode;
+ struct udf_fileident_bh ofibh, nfibh;
+ struct FileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL, ocfi, ncfi;
+ struct buffer_head *dir_bh = NULL;
+ int retval = -ENOENT;
+
+ old_inode = old_dentry->d_inode;
+ ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
+ if (!ofi || udf_get_lb_pblock(old_dir->i_sb, lelb_to_cpu(ocfi.icb.extLocation), 0) !=
+ old_inode->i_ino)
+ {
+ goto end_rename;
+ }
+
+ new_inode = new_dentry->d_inode;
+ nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi);
+ if (nfi)
+ {
+ if (!new_inode)
+ {
+ if (nfibh.sbh != nfibh.ebh)
+ udf_release_data(nfibh.ebh);
+ udf_release_data(nfibh.sbh);
+ nfi = NULL;
+ }
+ else
+ {
+/*
+ DQUOT_INIT(new_inode);
+*/
+ }
+ }
+ if (S_ISDIR(old_inode->i_mode))
+ {
+ Uint32 offset = UDF_I_EXT0OFFS(old_inode);
+
+ if (new_inode)
+ {
+ retval = -ENOTEMPTY;
+ if (!empty_dir(new_inode))
+ goto end_rename;
+ }
+ retval = -EIO;
+ dir_bh = udf_bread(old_inode, 0, 0, &retval);
+ if (!dir_bh)
+ goto end_rename;
+ dir_fi = udf_get_fileident(dir_bh->b_data, old_inode->i_sb->s_blocksize, &offset);
+ if (!dir_fi)
+ goto end_rename;
+ if (udf_get_lb_pblock(old_inode->i_sb, cpu_to_lelb(dir_fi->icb.extLocation), 0) !=
+ old_dir->i_ino)
+ {
+ goto end_rename;
+ }
+ retval = -EMLINK;
+ if (!new_inode && new_dir->i_nlink >= (256<<sizeof(new_dir->i_nlink))-1)
+ goto end_rename;
+ }
+ if (!nfi)
+ {
+ nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, &retval);
+ if (!nfi)
+ goto end_rename;
+ }
+ new_dir->i_version = ++event;
+
+ /*
+ * ok, that's it
+ */
+ ncfi.fileVersionNum = ocfi.fileVersionNum;
+ ncfi.fileCharacteristics = ocfi.fileCharacteristics;
+ memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(long_ad));
+ udf_write_fi(&ncfi, nfi, &nfibh, NULL, NULL);
+
+ udf_delete_entry(ofi, &ofibh, &ocfi);
+
+ old_dir->i_version = ++event;
+ if (new_inode)
+ {
+ new_inode->i_nlink--;
+ new_inode->i_ctime = CURRENT_TIME;
+ UDF_I_UCTIME(new_inode) = CURRENT_UTIME;
+ mark_inode_dirty(new_inode);
+ }
+ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+ UDF_I_UCTIME(old_dir) = UDF_I_UMTIME(old_dir) = CURRENT_UTIME;
+ mark_inode_dirty(old_dir);
+
+ if (dir_bh)
+ {
+ dir_fi->icb.extLocation = lelb_to_cpu(UDF_I_LOCATION(new_dir));
+ udf_update_tag((char *)dir_fi, sizeof(struct FileIdentDesc) +
+ cpu_to_le16(dir_fi->lengthOfImpUse));
+ if (UDF_I_ALLOCTYPE(old_inode) == ICB_FLAG_AD_IN_ICB)
+ {
+ mark_inode_dirty(old_inode);
+ old_inode->i_version = ++event;
+ }
+ else
+ mark_buffer_dirty(dir_bh, 1);
+ old_dir->i_nlink --;
+ mark_inode_dirty(old_dir);
+ if (new_inode)
+ {
+ new_inode->i_nlink --;
+ mark_inode_dirty(new_inode);
+ }
+ else
+ {
+ new_dir->i_nlink ++;
+ mark_inode_dirty(new_dir);
+ }
+ }
+
+ retval = 0;
+
+end_rename:
+ udf_release_data(dir_bh);
+ if (ofi)
+ {
+ if (ofibh.sbh != ofibh.ebh)
+ udf_release_data(ofibh.ebh);
+ udf_release_data(ofibh.sbh);
+ }
+ if (nfi)
+ {
+ if (nfibh.sbh != nfibh.ebh)
+ udf_release_data(nfibh.ebh);
+ udf_release_data(nfibh.sbh);
+ }
+ return retval;
+}
diff --git a/fs/udf/partition.c b/fs/udf/partition.c
new file mode 100644
index 000000000..ecfabb849
--- /dev/null
+++ b/fs/udf/partition.c
@@ -0,0 +1,190 @@
+/*
+ * partition.c
+ *
+ * PURPOSE
+ * Partition handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ *
+ * (C) 1998-1999 Ben Fennema
+ *
+ * HISTORY
+ *
+ * 12/06/98 blf Created file.
+ *
+ */
+
+#include "udfdecl.h"
+#include "udf_sb.h"
+#include "udf_i.h"
+
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/udf_fs.h>
+
+extern Uint32 udf_get_pblock(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
+{
+ Uint16 ident;
+
+ if (partition >= UDF_SB_NUMPARTS(sb))
+ {
+ udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
+ block, partition, offset);
+ return 0xFFFFFFFF;
+ }
+ switch (UDF_SB_PARTTYPE(sb, partition))
+ {
+ case UDF_TYPE1_MAP15:
+ {
+ return UDF_SB_PARTROOT(sb, partition) + block + offset;
+ }
+ case UDF_VIRTUAL_MAP15:
+ case UDF_VIRTUAL_MAP20:
+ {
+ struct buffer_head *bh = NULL;
+ Uint32 newblock;
+ Uint32 index;
+ Uint32 loc;
+
+ index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(Uint32);
+
+
+ if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries)
+ {
+ udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
+ block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
+ return 0xFFFFFFFF;
+ }
+
+ if (block >= index)
+ {
+ block -= index;
+ newblock = 1 + (block / (sb->s_blocksize / sizeof(Uint32)));
+ index = block % (sb->s_blocksize / sizeof(Uint32));
+ }
+ else
+ {
+ newblock = 0;
+ index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(Uint32) + block;
+ }
+
+ loc = udf_locked_block_map(UDF_SB_VAT(sb), newblock);
+
+ if (!(bh = bread(sb->s_dev, loc, sb->s_blocksize)))
+ {
+ udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
+ sb, block, partition, loc, index);
+ return 0xFFFFFFFF;
+ }
+
+ loc = le32_to_cpu(((Uint32 *)bh->b_data)[index]);
+
+ udf_release_data(bh);
+
+ if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
+ {
+ udf_debug("recursive call to udf_get_pblock!\n");
+ return 0xFFFFFFFF;
+ }
+
+ return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
+ }
+ case UDF_SPARABLE_MAP15:
+ {
+ Uint32 newblock = UDF_SB_PARTROOT(sb, partition) + block + offset;
+ Uint32 spartable = UDF_SB_TYPESPAR(sb, partition).s_spar_loc;
+ Uint32 plength = UDF_SB_TYPESPAR(sb,partition).s_spar_plen;
+ Uint32 packet = (block + offset) & (~(plength-1));
+ struct buffer_head *bh = NULL;
+ struct SparingTable *st;
+ SparingEntry *se;
+
+ bh = udf_read_tagged(sb, spartable, spartable, &ident);
+
+ if (!bh)
+ {
+ printk(KERN_ERR "udf: udf_read_tagged(%p,%d,%d)\n",
+ sb, spartable, spartable);
+ return 0xFFFFFFFF;
+ }
+
+ st = (struct SparingTable *)bh->b_data;
+ if (ident == 0)
+ {
+ if (!strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING)))
+ {
+ Uint16 rtl = le16_to_cpu(st->reallocationTableLen);
+ Uint16 index;
+
+ /* If the sparing table span multiple blocks, find out which block we are on */
+
+ se = &(st->mapEntry[0]);
+
+ if (rtl * sizeof(SparingEntry) + sizeof(struct SparingTable) > sb->s_blocksize)
+ {
+ index = (sb->s_blocksize - sizeof(struct SparingTable)) / sizeof(SparingEntry);
+ if (le32_to_cpu(se[index-1].origLocation) == packet)
+ {
+ udf_release_data(bh);
+ return le32_to_cpu(se[index].mappedLocation) | (newblock & (plength-1));
+ }
+ else if (le32_to_cpu(se[index-1].origLocation) < packet)
+ {
+ do
+ {
+ udf_release_data(bh);
+ bh = udf_tread(sb, spartable, sb->s_blocksize);
+ if (!bh)
+ return 0xFFFFFFFF;
+ se = (SparingEntry *)bh->b_data;
+ spartable ++;
+ rtl -= index;
+ index = sb->s_blocksize / sizeof(SparingEntry);
+
+ if (le32_to_cpu(se[index].origLocation) == packet)
+ {
+ udf_release_data(bh);
+ return le32_to_cpu(se[index].mappedLocation) | (newblock & (plength-1));
+ }
+ } while (rtl * sizeof(SparingEntry) > sb->s_blocksize &&
+ le32_to_cpu(se[index-1].origLocation) < packet);
+ }
+ }
+
+ for (index=0; index<rtl; index++)
+ {
+ if (le32_to_cpu(se[index].origLocation) == packet)
+ {
+ udf_release_data(bh);
+ return le32_to_cpu(se[index].mappedLocation) | (newblock & (plength-1));
+ }
+ else if (le32_to_cpu(se[index].origLocation) > packet)
+ {
+ udf_release_data(bh);
+ return newblock;
+ }
+ }
+
+ udf_release_data(bh);
+ return newblock;
+ }
+ }
+ udf_release_data(bh);
+ }
+ }
+ return 0xFFFFFFFF;
+}
+
+extern Uint32 udf_get_lb_pblock(struct super_block *sb, lb_addr loc, Uint32 offset)
+{
+ return udf_get_pblock(sb, loc.logicalBlockNum, loc.partitionReferenceNum, offset);
+}
diff --git a/fs/udf/super.c b/fs/udf/super.c
new file mode 100644
index 000000000..c6ff2c6e2
--- /dev/null
+++ b/fs/udf/super.c
@@ -0,0 +1,1623 @@
+/*
+ * super.c
+ *
+ * PURPOSE
+ * Super block routines for the OSTA-UDF(tm) filesystem.
+ *
+ * DESCRIPTION
+ * OSTA-UDF(tm) = Optical Storage Technology Association
+ * Universal Disk Format.
+ *
+ * This code is based on version 2.00 of the UDF specification,
+ * and revision 3 of the ECMA 167 standard [equivalent to ISO 13346].
+ * http://www.osta.org/
+ * http://www.ecma.ch/
+ * http://www.iso.org/
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ *
+ * (C) 1998 Dave Boynton
+ * (C) 1998-1999 Ben Fennema
+ *
+ * HISTORY
+ *
+ * 09/24/98 dgb changed to allow compiling outside of kernel, and
+ * added some debugging.
+ * 10/01/98 dgb updated to allow (some) possibility of compiling w/2.0.34
+ * 10/16/98 attempting some multi-session support
+ * 10/17/98 added freespace count for "df"
+ * 11/11/98 gr added novrs option
+ * 11/26/98 dgb added fileset,anchor mount options
+ * 12/06/98 blf really hosed things royally. vat/sparing support. sequenced vol descs
+ * rewrote option handling based on isofs
+ * 12/20/98 find the free space bitmap (if it exists)
+ */
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#include "udfdecl.h"
+
+#include <linux/blkdev.h>
+#include <linux/malloc.h>
+#include <linux/kernel.h>
+#include <linux/locks.h>
+#include <linux/module.h>
+#include <linux/stat.h>
+#include <linux/cdrom.h>
+#include <linux/nls.h>
+#include <asm/byteorder.h>
+
+#include <linux/udf_fs.h>
+#include "udf_sb.h"
+#include "udf_i.h"
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+static char error_buf[1024];
+
+/* These are the "meat" - everything else is stuffing */
+static struct super_block *udf_read_super(struct super_block *, void *, int);
+static void udf_put_super(struct super_block *);
+static int udf_remount_fs(struct super_block *, int *, char *);
+static int udf_check_valid(struct super_block *, int, int);
+static int udf_vrs(struct super_block *sb, int silent);
+static int udf_load_partition(struct super_block *, lb_addr *);
+static int udf_load_logicalvol(struct super_block *, struct buffer_head *, lb_addr *);
+static void udf_load_logicalvolint(struct super_block *, extent_ad);
+static int udf_find_anchor(struct super_block *, int, int);
+static int udf_find_fileset(struct super_block *, lb_addr *, lb_addr *);
+static void udf_load_pvoldesc(struct super_block *, struct buffer_head *);
+static void udf_load_fileset(struct super_block *, struct buffer_head *, lb_addr *);
+static void udf_load_partdesc(struct super_block *, struct buffer_head *);
+static void udf_open_lvid(struct super_block *);
+static void udf_close_lvid(struct super_block *);
+static unsigned int udf_count_free(struct super_block *);
+
+/* version specific functions */
+static int udf_statfs(struct super_block *, struct statfs *, int);
+
+/* UDF filesystem type */
+static struct file_system_type udf_fstype = {
+ "udf", /* name */
+ FS_REQUIRES_DEV, /* fs_flags */
+ udf_read_super, /* read_super */
+ NULL /* next */
+};
+
+/* Superblock operations */
+static struct super_operations udf_sb_ops =
+{
+ udf_read_inode, /* read_inode */
+#ifdef CONFIG_UDF_RW
+ udf_write_inode, /* write_inode */
+#else
+ NULL, /* write_inode */
+#endif
+ udf_put_inode, /* put_inode */
+#ifdef CONFIG_UDF_RW
+ udf_delete_inode, /* delete_inode */
+#else
+ NULL, /* delete_inode */
+#endif
+ NULL, /* notify_change */
+ udf_put_super, /* put_super */
+ NULL, /* write_super */
+ udf_statfs, /* statfs */
+ udf_remount_fs, /* remount_fs */
+ NULL, /* clear_inode */
+ NULL, /* umount_begin */
+};
+
+struct udf_options
+{
+ unsigned char novrs;
+ unsigned char utf8;
+ unsigned int blocksize;
+ unsigned int session;
+ unsigned int lastblock;
+ unsigned int anchor;
+ unsigned int volume;
+ unsigned short partition;
+ unsigned int fileset;
+ unsigned int rootdir;
+ unsigned int flags;
+ mode_t umask;
+ gid_t gid;
+ uid_t uid;
+ char *iocharset;
+};
+
+#if defined(MODULE)
+
+/*
+ * cleanup_module
+ *
+ * PURPOSE
+ * Unregister the UDF filesystem type.
+ *
+ * DESCRIPTION
+ * Clean-up before the module is unloaded.
+ * This routine only applies when compiled as a module.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+int
+cleanup_module(void)
+{
+ printk(KERN_NOTICE "udf: unregistering filesystem\n");
+ return unregister_filesystem(&udf_fstype);
+}
+
+/*
+ * init_module / init_udf_fs
+ *
+ * PURPOSE
+ * Register the UDF filesystem type.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+int init_module(void)
+#else /* if !defined(MODULE) */
+int __init init_udf_fs(void)
+#endif
+{
+ printk(KERN_NOTICE "udf: registering filesystem\n");
+ {
+ struct super_block sb;
+ int size;
+
+ size = sizeof(struct super_block) +
+ (long)&sb.u - (long)&sb;
+ if ( size < sizeof(struct udf_sb_info) )
+ {
+ printk(KERN_ERR "udf: Danger! Kernel was compiled without enough room for udf_sb_info\n");
+ printk(KERN_ERR "udf: Kernel has room for %u bytes, udf needs %u\n",
+ size, sizeof(struct udf_sb_info));
+ return 0;
+ }
+ }
+ return register_filesystem(&udf_fstype);
+}
+
+/*
+ * udf_parse_options
+ *
+ * PURPOSE
+ * Parse mount options.
+ *
+ * DESCRIPTION
+ * The following mount options are supported:
+ *
+ * gid= Set the default group.
+ * umask= Set the default umask.
+ * uid= Set the default user.
+ * unhide Show otherwise hidden files.
+ * undelete Show deleted files in lists.
+ * strict Set strict conformance (unused)
+ * utf8 (unused)
+ * iocharset (unused)
+ *
+ * The remaining are for debugging and disaster recovery:
+ *
+ * bs= Set the block size. (may not work unless 2048)
+ * novrs Skip volume sequence recognition
+ *
+ * The following expect a offset from 0.
+ *
+ * session= Set the CDROM session (default= last session)
+ * anchor= Override standard anchor location. (default= 256)
+ * volume= Override the VolumeDesc location. (unused)
+ * partition= Override the PartitionDesc location. (unused)
+ * lastblock= Set the last block of the filesystem/
+ *
+ * The following expect a offset from the partition root.
+ *
+ * fileset= Override the fileset block location. (unused)
+ * rootdir= Override the root directory location. (unused)
+ * WARNING: overriding the rootdir to a non-directory may
+ * yield highly unpredictable results.
+ *
+ * PRE-CONDITIONS
+ * options Pointer to mount options string.
+ * uopts Pointer to mount options variable.
+ *
+ * POST-CONDITIONS
+ * <return> 0 Mount options parsed okay.
+ * <return> -1 Error parsing mount options.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+
+static int
+udf_parse_options(char *options, struct udf_options *uopt)
+{
+ char *opt, *val;
+
+ uopt->novrs = 0;
+ uopt->blocksize = 2048;
+ uopt->partition = 0xFFFF;
+ uopt->session = 0xFFFFFFFF;
+ uopt->lastblock = 0xFFFFFFFF;
+ uopt->anchor = 0xFFFFFFFF;
+ uopt->volume = 0xFFFFFFFF;
+ uopt->rootdir = 0xFFFFFFFF;
+ uopt->fileset = 0xFFFFFFFF;
+ uopt->iocharset = NULL;
+
+ if (!options)
+ return 1;
+
+ for (opt = strtok(options, ","); opt; opt = strtok(NULL, ","))
+ {
+ /* Make "opt=val" into two strings */
+ val = strchr(opt, '=');
+ if (val)
+ *(val++) = 0;
+ if (!strcmp(opt, "novrs") && !val)
+ uopt->novrs = 1;
+ else if (!strcmp(opt, "utf8") && !val)
+ uopt->utf8 = 1;
+ else if (!strcmp(opt, "bs") && val)
+ uopt->blocksize = simple_strtoul(val, NULL, 0);
+ else if (!strcmp(opt, "unhide") && !val)
+ uopt->flags |= UDF_FLAG_UNHIDE;
+ else if (!strcmp(opt, "undelete") && !val)
+ uopt->flags |= UDF_FLAG_UNDELETE;
+ else if (!strcmp(opt, "gid") && val)
+ uopt->gid = simple_strtoul(val, NULL, 0);
+ else if (!strcmp(opt, "umask") && val)
+ uopt->umask = simple_strtoul(val, NULL, 0);
+ else if (!strcmp(opt, "strict") && !val)
+ uopt->flags |= UDF_FLAG_STRICT;
+ else if (!strcmp(opt, "uid") && val)
+ uopt->uid = simple_strtoul(val, NULL, 0);
+ else if (!strcmp(opt, "session") && val)
+ uopt->session = simple_strtoul(val, NULL, 0);
+ else if (!strcmp(opt, "lastblock") && val)
+ uopt->lastblock = simple_strtoul(val, NULL, 0);
+ else if (!strcmp(opt, "anchor") && val)
+ uopt->anchor = simple_strtoul(val, NULL, 0);
+ else if (!strcmp(opt, "volume") && val)
+ uopt->volume = simple_strtoul(val, NULL, 0);
+ else if (!strcmp(opt, "partition") && val)
+ uopt->partition = simple_strtoul(val, NULL, 0);
+ else if (!strcmp(opt, "fileset") && val)
+ uopt->fileset = simple_strtoul(val, NULL, 0);
+ else if (!strcmp(opt, "rootdir") && val)
+ uopt->rootdir = simple_strtoul(val, NULL, 0);
+ else if (!strcmp(opt, "iocharset") && val)
+ {
+ uopt->iocharset = val;
+ while (*val && *val != ',')
+ val ++;
+ if (val == uopt->iocharset)
+ return 0;
+ *val = 0;
+ }
+ else if (val)
+ {
+ printk(KERN_ERR "udf: bad mount option \"%s=%s\"\n",
+ opt, val);
+ return 0;
+ }
+ else
+ {
+ printk(KERN_ERR "udf: bad mount option \"%s\"\n",
+ opt);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+udf_remount_fs(struct super_block *sb, int *flags, char *options)
+{
+ struct udf_options uopt;
+
+ uopt.flags = UDF_SB(sb)->s_flags ;
+ uopt.uid = UDF_SB(sb)->s_uid ;
+ uopt.gid = UDF_SB(sb)->s_gid ;
+ uopt.umask = UDF_SB(sb)->s_umask ;
+ uopt.utf8 = UDF_SB(sb)->s_utf8 ;
+
+ if ( !udf_parse_options(options, &uopt) )
+ return -EINVAL;
+
+ UDF_SB(sb)->s_flags = uopt.flags;
+ UDF_SB(sb)->s_uid = uopt.uid;
+ UDF_SB(sb)->s_gid = uopt.gid;
+ UDF_SB(sb)->s_umask = uopt.umask;
+ UDF_SB(sb)->s_utf8 = uopt.utf8;
+
+ if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+ return 0;
+ if (*flags & MS_RDONLY)
+ udf_close_lvid(sb);
+ else
+ udf_open_lvid(sb);
+
+ return 0;
+}
+
+/*
+ * udf_set_blocksize
+ *
+ * PURPOSE
+ * Set the block size to be used in all transfers.
+ *
+ * DESCRIPTION
+ * To allow room for a DMA transfer, it is best to guess big when unsure.
+ * This routine picks 2048 bytes as the blocksize when guessing. This
+ * should be adequate until devices with larger block sizes become common.
+ *
+ * Note that the Linux kernel can currently only deal with blocksizes of
+ * 512, 1024, 2048, 4096, and 8192 bytes.
+ *
+ * PRE-CONDITIONS
+ * sb Pointer to _locked_ superblock.
+ *
+ * POST-CONDITIONS
+ * sb->s_blocksize Blocksize.
+ * sb->s_blocksize_bits log2 of blocksize.
+ * <return> 0 Blocksize is valid.
+ * <return> 1 Blocksize is invalid.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+static int
+udf_set_blocksize(struct super_block *sb, int bsize)
+{
+ /* Use specified block size if specified */
+ sb->s_blocksize = get_hardblocksize(sb->s_dev);
+ sb->s_blocksize = sb->s_blocksize ? sb->s_blocksize : 2048;
+ if (bsize > sb->s_blocksize)
+ sb->s_blocksize = bsize;
+
+ /* Block size must be an even multiple of 512 */
+ switch (sb->s_blocksize) {
+ case 512: sb->s_blocksize_bits = 9; break;
+ case 1024: sb->s_blocksize_bits = 10; break;
+ case 2048: sb->s_blocksize_bits = 11; break;
+ case 4096: sb->s_blocksize_bits = 12; break;
+ case 8192: sb->s_blocksize_bits = 13; break;
+ default:
+ {
+ udf_debug("Bad block size (%ld)\n", sb->s_blocksize);
+ printk(KERN_ERR "udf: bad block size (%ld)\n", sb->s_blocksize);
+ return 0;
+ }
+ }
+
+ /* Set the block size */
+ set_blocksize(sb->s_dev, sb->s_blocksize);
+ return sb->s_blocksize;
+}
+
+static int
+udf_vrs(struct super_block *sb, int silent)
+{
+ struct VolStructDesc *vsd = NULL;
+ int sector = 32768;
+ struct buffer_head *bh = NULL;
+ int iso9660=0;
+ int nsr02=0;
+ int nsr03=0;
+
+ /* Block size must be a multiple of 512 */
+ if (sb->s_blocksize & 511)
+ return sector;
+
+ sector += (UDF_SB_SESSION(sb) << sb->s_blocksize_bits);
+
+ udf_debug("Starting at sector %u (%ld byte sectors)\n",
+ (sector >> sb->s_blocksize_bits), sb->s_blocksize);
+ /* Process the sequence (if applicable) */
+ for (;!nsr02 && !nsr03; sector += 2048)
+ {
+ /* Read a block */
+ bh = udf_tread(sb, sector >> sb->s_blocksize_bits, 2048);
+ if (!bh)
+ break;
+
+ /* Look for ISO descriptors */
+ vsd = (struct VolStructDesc *)(bh->b_data +
+ (sector & (sb->s_blocksize - 1)));
+
+ if (vsd->stdIdent[0] == 0)
+ {
+ udf_release_data(bh);
+ break;
+ }
+ else if (!strncmp(vsd->stdIdent, STD_ID_CD001, STD_ID_LEN))
+ {
+ iso9660 = sector;
+ switch (vsd->structType)
+ {
+ case 0:
+ udf_debug("ISO9660 Boot Record found\n");
+ break;
+ case 1:
+ udf_debug("ISO9660 Primary Volume Descriptor found\n");
+ break;
+ case 2:
+ udf_debug("ISO9660 Supplementary Volume Descriptor found\n");
+ break;
+ case 3:
+ udf_debug("ISO9660 Volume Partition Descriptor found\n");
+ break;
+ case 255:
+ udf_debug("ISO9660 Volume Descriptor Set Terminator found\n");
+ break;
+ default:
+ udf_debug("ISO9660 VRS (%u) found\n", vsd->structType);
+ break;
+ }
+ }
+ else if (!strncmp(vsd->stdIdent, STD_ID_BEA01, STD_ID_LEN))
+ {
+ }
+ else if (!strncmp(vsd->stdIdent, STD_ID_TEA01, STD_ID_LEN))
+ {
+ udf_release_data(bh);
+ break;
+ }
+ else if (!strncmp(vsd->stdIdent, STD_ID_NSR02, STD_ID_LEN))
+ {
+ nsr02 = sector;
+ }
+ else if (!strncmp(vsd->stdIdent, STD_ID_NSR03, STD_ID_LEN))
+ {
+ nsr03 = sector;
+ }
+ udf_release_data(bh);
+ }
+
+ if (nsr03)
+ return nsr03;
+ else if (nsr02)
+ return nsr02;
+ else if (sector - (UDF_SB_SESSION(sb) << sb->s_blocksize_bits) == 32768)
+ return -1;
+ else
+ return 0;
+}
+
+/*
+ * udf_find_anchor
+ *
+ * PURPOSE
+ * Find an anchor volume descriptor.
+ *
+ * PRE-CONDITIONS
+ * sb Pointer to _locked_ superblock.
+ * lastblock Last block on media.
+ *
+ * POST-CONDITIONS
+ * <return> 1 if not found, 0 if ok
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+static int
+udf_find_anchor(struct super_block *sb, int useranchor, int lastblock)
+{
+ int varlastblock = udf_variable_to_fixed(lastblock);
+ int last[] = { lastblock, lastblock - 2,
+ lastblock - 150, lastblock - 152,
+ varlastblock, varlastblock - 2,
+ varlastblock - 150, varlastblock - 152 };
+ struct buffer_head *bh = NULL;
+ Uint16 ident;
+ Uint32 location;
+ int i;
+
+ UDF_SB_ANCHOR(sb)[0] = 0;
+ UDF_SB_ANCHOR(sb)[1] = 0;
+ UDF_SB_ANCHOR(sb)[2] = 0;
+ UDF_SB_ANCHOR(sb)[3] = 256 + UDF_SB_SESSION(sb);
+
+ lastblock = 0;
+
+ /* Search for an anchor volume descriptor pointer */
+
+ /* according to spec, anchor is in either:
+ * block 256
+ * lastblock-256
+ * lastblock
+ * however, if the disc isn't closed, it could be 512 */
+
+ for (i=0; (!lastblock && i<sizeof(last)/sizeof(int)); i++)
+ {
+ if (!(bh = bread(sb->s_dev, last[i], sb->s_blocksize)))
+ {
+ ident = location = 0;
+ }
+ else
+ {
+ ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
+ location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
+ udf_release_data(bh);
+ }
+
+ if (ident == TID_ANCHOR_VOL_DESC_PTR)
+ {
+ if (location == last[i] - UDF_SB_SESSION(sb))
+ {
+ lastblock = UDF_SB_ANCHOR(sb)[0] = last[i];
+ UDF_SB_ANCHOR(sb)[1] = last[i] - 256;
+ }
+ else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb))
+ {
+ UDF_SB(sb)->s_flags |= UDF_FLAG_VARCONV;
+ lastblock = UDF_SB_ANCHOR(sb)[0] = udf_variable_to_fixed(last[i]);
+ UDF_SB_ANCHOR(sb)[1] = lastblock - 256;
+ }
+ else
+ udf_debug("Anchor found at block %d, location mismatch %d.\n",
+ last[i], location);
+ }
+ else if (ident == TID_FILE_ENTRY || ident == TID_EXTENDED_FILE_ENTRY)
+ {
+ lastblock = last[i];
+ UDF_SB_ANCHOR(sb)[2] = 512 + UDF_SB_SESSION(sb);
+ }
+ else
+ {
+ if (!(bh = bread(sb->s_dev, last[i] - 256, sb->s_blocksize)))
+ {
+ ident = location = 0;
+ }
+ else
+ {
+ ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
+ location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
+ udf_release_data(bh);
+ }
+
+ if (ident == TID_ANCHOR_VOL_DESC_PTR &&
+ location == last[i] - 256 - UDF_SB_SESSION(sb))
+ {
+ lastblock = last[i];
+ UDF_SB_ANCHOR(sb)[1] = last[i] - 256;
+ }
+ else
+ {
+ if (!(bh = bread(sb->s_dev, last[i] - 312 - UDF_SB_SESSION(sb),
+ sb->s_blocksize)))
+ {
+ ident = location = 0;
+ }
+ else
+ {
+ ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
+ location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
+ udf_release_data(bh);
+ }
+
+ if (ident == TID_ANCHOR_VOL_DESC_PTR &&
+ location == udf_variable_to_fixed(last[i]) - 256)
+ {
+ UDF_SB(sb)->s_flags |= UDF_FLAG_VARCONV;
+ lastblock = udf_variable_to_fixed(last[i]);
+ UDF_SB_ANCHOR(sb)[1] = lastblock - 256;
+ }
+ }
+ }
+ }
+
+ if (!lastblock)
+ {
+ /* We havn't found the lastblock. check 312 */
+ if ((bh = bread(sb->s_dev, 312 + UDF_SB_SESSION(sb), sb->s_blocksize)))
+ {
+ ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
+ location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
+ udf_release_data(bh);
+
+ if (ident == TID_ANCHOR_VOL_DESC_PTR && location == 256)
+ UDF_SB(sb)->s_flags |= UDF_FLAG_VARCONV;
+ }
+ }
+
+ for (i=0; i<sizeof(UDF_SB_ANCHOR(sb))/sizeof(int); i++)
+ {
+ if (UDF_SB_ANCHOR(sb)[i])
+ {
+ if (!(bh = udf_read_tagged(sb,
+ UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i], &ident)))
+ {
+ UDF_SB_ANCHOR(sb)[i] = 0;
+ }
+ else
+ {
+ udf_release_data(bh);
+ if ((ident != TID_ANCHOR_VOL_DESC_PTR) && (i ||
+ (ident != TID_FILE_ENTRY && ident != TID_EXTENDED_FILE_ENTRY)))
+ {
+ UDF_SB_ANCHOR(sb)[i] = 0;
+ }
+ }
+ }
+ else if (useranchor != 0xFFFFFFFF)
+ {
+ UDF_SB_ANCHOR(sb)[i] = useranchor;
+ useranchor = 0xFFFFFFFF;
+ i --;
+ }
+ }
+
+ return lastblock;
+}
+
+static int
+udf_find_fileset(struct super_block *sb, lb_addr *fileset, lb_addr *root)
+{
+ struct buffer_head *bh = NULL;
+ long lastblock;
+ Uint16 ident;
+
+ if (fileset->logicalBlockNum != 0xFFFFFFFF ||
+ fileset->partitionReferenceNum != 0xFFFF)
+ {
+ bh = udf_read_ptagged(sb, *fileset, 0, &ident);
+
+ if (!bh)
+ return 1;
+ else if (ident != TID_FILE_SET_DESC)
+ {
+ udf_release_data(bh);
+ return 1;
+ }
+
+ }
+
+ if (!bh) /* Search backwards through the partitions */
+ {
+ lb_addr newfileset;
+
+ return 1;
+
+ for (newfileset.partitionReferenceNum=UDF_SB_NUMPARTS(sb)-1;
+ (newfileset.partitionReferenceNum != 0xFFFF &&
+ fileset->logicalBlockNum == 0xFFFFFFFF &&
+ fileset->partitionReferenceNum == 0xFFFF);
+ newfileset.partitionReferenceNum--)
+ {
+ lastblock = UDF_SB_PARTLEN(sb, newfileset.partitionReferenceNum);
+ newfileset.logicalBlockNum = 0;
+
+ do
+ {
+ bh = udf_read_ptagged(sb, newfileset, 0, &ident);
+ if (!bh)
+ {
+ newfileset.logicalBlockNum ++;
+ continue;
+ }
+
+ switch (ident)
+ {
+ case TID_SPACE_BITMAP_DESC:
+ {
+ struct SpaceBitmapDesc *sp;
+ sp = (struct SpaceBitmapDesc *)bh->b_data;
+ newfileset.logicalBlockNum += 1 +
+ ((le32_to_cpu(sp->numOfBytes) + sizeof(struct SpaceBitmapDesc) - 1)
+ >> sb->s_blocksize_bits);
+ udf_release_data(bh);
+ break;
+ }
+ case TID_FILE_SET_DESC:
+ {
+ *fileset = newfileset;
+ break;
+ }
+ default:
+ {
+ newfileset.logicalBlockNum ++;
+ udf_release_data(bh);
+ bh = NULL;
+ break;
+ }
+ }
+ }
+ while (newfileset.logicalBlockNum < lastblock &&
+ fileset->logicalBlockNum == 0xFFFFFFFF &&
+ fileset->partitionReferenceNum == 0xFFFF);
+ }
+ }
+
+ if ((fileset->logicalBlockNum != 0xFFFFFFFF ||
+ fileset->partitionReferenceNum != 0xFFFF) && bh)
+ {
+ udf_debug("Fileset at block=%d, partition=%d\n",
+ fileset->logicalBlockNum, fileset->partitionReferenceNum);
+
+ UDF_SB_PARTITION(sb) = fileset->partitionReferenceNum;
+ udf_load_fileset(sb, bh, root);
+ udf_release_data(bh);
+ return 0;
+ }
+ return 1;
+}
+
+static void
+udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
+{
+ struct PrimaryVolDesc *pvoldesc;
+ time_t recording;
+ struct ustr instr;
+ struct ustr outstr;
+
+ pvoldesc = (struct PrimaryVolDesc *)bh->b_data;
+
+ if ( udf_stamp_to_time(&recording, lets_to_cpu(pvoldesc->recordingDateAndTime)) )
+ {
+ timestamp ts;
+ ts = lets_to_cpu(pvoldesc->recordingDateAndTime);
+ udf_debug("recording time %ld, %u/%u/%u %u:%u (%x)\n",
+ recording, ts.year, ts.month, ts.day, ts.hour, ts.minute,
+ ts.typeAndTimezone);
+ UDF_SB_RECORDTIME(sb) = recording;
+ }
+
+ if ( !udf_build_ustr(&instr, pvoldesc->volIdent, 32) )
+ {
+ if (!udf_CS0toUTF8(&outstr, &instr))
+ {
+ udf_debug("volIdent[] = '%s'\n", outstr.u_name);
+ strncpy( UDF_SB_VOLIDENT(sb), outstr.u_name, outstr.u_len);
+ }
+ }
+
+ if ( !udf_build_ustr(&instr, pvoldesc->volSetIdent, 128) )
+ {
+ if (!udf_CS0toUTF8(&outstr, &instr))
+ udf_debug("volSetIdent[] = '%s'\n", outstr.u_name);
+ }
+}
+
+static void
+udf_load_fileset(struct super_block *sb, struct buffer_head *bh, lb_addr *root)
+{
+ struct FileSetDesc *fset;
+
+ fset = (struct FileSetDesc *)bh->b_data;
+
+ *root = lelb_to_cpu(fset->rootDirectoryICB.extLocation);
+
+ UDF_SB_SERIALNUM(sb) = le16_to_cpu(fset->descTag.tagSerialNum);
+
+ udf_debug("Rootdir at block=%d, partition=%d\n",
+ root->logicalBlockNum, root->partitionReferenceNum);
+}
+
+static void
+udf_load_partdesc(struct super_block *sb, struct buffer_head *bh)
+{
+ struct PartitionDesc *p;
+ int i;
+
+ p=(struct PartitionDesc *)bh->b_data;
+
+ for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
+ {
+ udf_debug("Searching map: (%d == %d)\n",
+ UDF_SB_PARTMAPS(sb)[i].s_partition_num, le16_to_cpu(p->partitionNumber));
+ if (UDF_SB_PARTMAPS(sb)[i].s_partition_num == le16_to_cpu(p->partitionNumber))
+ {
+ UDF_SB_PARTLEN(sb,i) = le32_to_cpu(p->partitionLength); /* blocks */
+ UDF_SB_PARTROOT(sb,i) = le32_to_cpu(p->partitionStartingLocation) + UDF_SB_SESSION(sb);
+ UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap = 0xFFFFFFFF;
+
+ if (!strcmp(p->partitionContents.ident, PARTITION_CONTENTS_NSR02) ||
+ !strcmp(p->partitionContents.ident, PARTITION_CONTENTS_NSR03))
+ {
+ struct PartitionHeaderDesc *phd;
+
+ phd = (struct PartitionHeaderDesc *)(p->partitionContentsUse);
+ if (phd->unallocatedSpaceTable.extLength)
+ udf_debug("unallocatedSpaceTable (part %d)\n", i);
+ if (phd->unallocatedSpaceBitmap.extLength)
+ {
+ UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap =
+ le32_to_cpu(phd->unallocatedSpaceBitmap.extPosition);
+ udf_debug("unallocatedSpaceBitmap (part %d) @ %d\n",
+ i, UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap);
+ }
+ if (phd->partitionIntegrityTable.extLength)
+ udf_debug("partitionIntegrityTable (part %d)\n", i);
+ if (phd->freedSpaceTable.extLength)
+ udf_debug("freedSpaceTable (part %d)\n", i);
+ if (phd->freedSpaceBitmap.extLength)
+ udf_debug("freedSpaceBitmap (part %d\n", i);
+ }
+ break;
+ }
+ }
+ if (i == UDF_SB_NUMPARTS(sb))
+ {
+ udf_debug("Partition (%d) not found in partition map\n", le16_to_cpu(p->partitionNumber));
+ }
+ else
+ {
+ udf_debug("Partition (%d:%d type %x) starts at physical %d, block length %d\n",
+ le16_to_cpu(p->partitionNumber), i, UDF_SB_PARTTYPE(sb,i),
+ UDF_SB_PARTROOT(sb,i), UDF_SB_PARTLEN(sb,i));
+ }
+}
+
+static int
+udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, lb_addr *fileset)
+{
+ struct LogicalVolDesc *lvd;
+ int i, offset;
+ Uint8 type;
+
+ lvd = (struct LogicalVolDesc *)bh->b_data;
+
+ UDF_SB_NUMPARTS(sb) = le32_to_cpu(lvd->numPartitionMaps);
+ UDF_SB_ALLOC_PARTMAPS(sb, UDF_SB_NUMPARTS(sb));
+
+ for (i=0,offset=0;
+ i<UDF_SB_NUMPARTS(sb) && offset<le32_to_cpu(lvd->mapTableLength);
+ i++,offset+=((struct GenericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapLength)
+ {
+ type = ((struct GenericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapType;
+ udf_debug("Partition (%d) type %d\n", i, type);
+ if (type == 1)
+ {
+ struct GenericPartitionMap1 *gpm1 = (struct GenericPartitionMap1 *)&(lvd->partitionMaps[offset]);
+ UDF_SB_PARTTYPE(sb,i) = UDF_TYPE1_MAP15;
+ UDF_SB_PARTVSN(sb,i) = le16_to_cpu(gpm1->volSeqNum);
+ UDF_SB_PARTNUM(sb,i) = le16_to_cpu(gpm1->partitionNum);
+ }
+ else if (type == 2)
+ {
+ struct UdfPartitionMap2 *upm2 = (struct UdfPartitionMap2 *)&(lvd->partitionMaps[offset]);
+ if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL, strlen(UDF_ID_VIRTUAL)))
+ {
+ if (le16_to_cpu(((Uint16 *)upm2->partIdent.identSuffix)[0]) == 0x0150)
+ UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP15;
+ else if (le16_to_cpu(((Uint16 *)upm2->partIdent.identSuffix)[0]) == 0x0200)
+ UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP20;
+ }
+ else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE)))
+ {
+ struct SparablePartitionMap *spm = (struct SparablePartitionMap *)&(lvd->partitionMaps[offset]);
+ UDF_SB_PARTTYPE(sb,i) = UDF_SPARABLE_MAP15;
+ UDF_SB_TYPESPAR(sb,i).s_spar_plen = le16_to_cpu(spm->packetLength);
+ UDF_SB_TYPESPAR(sb,i).s_spar_loc = le32_to_cpu(spm->locSparingTable[0]);
+ }
+ else
+ {
+ udf_debug("Unknown ident: %s\n", upm2->partIdent.ident);
+ continue;
+ }
+ UDF_SB_PARTVSN(sb,i) = le16_to_cpu(upm2->volSeqNum);
+ UDF_SB_PARTNUM(sb,i) = le16_to_cpu(upm2->partitionNum);
+ }
+ }
+
+ if (fileset)
+ {
+ long_ad *la = (long_ad *)&(lvd->logicalVolContentsUse[0]);
+
+ *fileset = lelb_to_cpu(la->extLocation);
+ udf_debug("FileSet found in LogicalVolDesc at block=%d, partition=%d\n",
+ fileset->logicalBlockNum,
+ fileset->partitionReferenceNum);
+ }
+ if (lvd->integritySeqExt.extLength)
+ udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt));
+ return 0;
+}
+
+/*
+ * udf_load_logicalvolint
+ *
+ */
+static void
+udf_load_logicalvolint(struct super_block *sb, extent_ad loc)
+{
+ struct buffer_head *bh = NULL;
+ Uint16 ident;
+
+ while ((bh = udf_read_tagged(sb, loc.extLocation, loc.extLocation, &ident)) &&
+ ident == TID_LOGICAL_VOL_INTEGRITY_DESC && loc.extLength > 0)
+ {
+ UDF_SB_LVIDBH(sb) = bh;
+
+ if (UDF_SB_LVID(sb)->nextIntegrityExt.extLength)
+ udf_load_logicalvolint(sb, leea_to_cpu(UDF_SB_LVID(sb)->nextIntegrityExt));
+
+ if (UDF_SB_LVIDBH(sb) != bh)
+ udf_release_data(bh);
+ loc.extLength -= sb->s_blocksize;
+ loc.extLocation ++;
+ }
+ if (UDF_SB_LVIDBH(sb) != bh)
+ udf_release_data(bh);
+}
+
+/*
+ * udf_process_sequence
+ *
+ * PURPOSE
+ * Process a main/reserve volume descriptor sequence.
+ *
+ * PRE-CONDITIONS
+ * sb Pointer to _locked_ superblock.
+ * block First block of first extent of the sequence.
+ * lastblock Lastblock of first extent of the sequence.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+static int
+udf_process_sequence(struct super_block *sb, long block, long lastblock, lb_addr *fileset)
+{
+ struct buffer_head *bh = NULL;
+ struct udf_vds_record vds[VDS_POS_LENGTH];
+ struct GenericDesc *gd;
+ int done=0;
+ int i,j;
+ Uint32 vdsn;
+ Uint16 ident;
+
+ memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
+
+ /* Read the main descriptor sequence */
+ for (;(!done && block <= lastblock); block++)
+ {
+
+ bh = udf_read_tagged(sb, block, block, &ident);
+ if (!bh)
+ break;
+
+ /* Process each descriptor (ISO 13346 3/8.3-8.4) */
+ gd = (struct GenericDesc *)bh->b_data;
+ vdsn = le32_to_cpu(gd->volDescSeqNum);
+ switch (ident)
+ {
+ case TID_PRIMARY_VOL_DESC: /* ISO 13346 3/10.1 */
+ if (vdsn >= vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum)
+ {
+ vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum = vdsn;
+ vds[VDS_POS_PRIMARY_VOL_DESC].block = block;
+ }
+ break;
+ case TID_VOL_DESC_PTR: /* ISO 13346 3/10.3 */
+ if (vdsn >= vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum)
+ {
+ vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum = vdsn;
+ vds[VDS_POS_VOL_DESC_PTR].block = block;
+ }
+ break;
+ case TID_IMP_USE_VOL_DESC: /* ISO 13346 3/10.4 */
+ if (vdsn >= vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum)
+ {
+ vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum = vdsn;
+ vds[VDS_POS_IMP_USE_VOL_DESC].block = block;
+ }
+ break;
+ case TID_PARTITION_DESC: /* ISO 13346 3/10.5 */
+ if (!vds[VDS_POS_PARTITION_DESC].block)
+ vds[VDS_POS_PARTITION_DESC].block = block;
+ break;
+ case TID_LOGICAL_VOL_DESC: /* ISO 13346 3/10.6 */
+ if (vdsn >= vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum)
+ {
+ vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum = vdsn;
+ vds[VDS_POS_LOGICAL_VOL_DESC].block = block;
+ }
+ break;
+ case TID_UNALLOC_SPACE_DESC: /* ISO 13346 3/10.8 */
+ if (vdsn >= vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum)
+ {
+ vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum = vdsn;
+ vds[VDS_POS_UNALLOC_SPACE_DESC].block = block;
+ }
+ break;
+ case TID_TERMINATING_DESC: /* ISO 13346 3/10.9 */
+ vds[VDS_POS_TERMINATING_DESC].block = block;
+ done = 1;
+ break;
+ }
+ udf_release_data(bh);
+ }
+ for (i=0; i<VDS_POS_LENGTH; i++)
+ {
+ if (vds[i].block)
+ {
+ bh = udf_read_tagged(sb, vds[i].block, vds[i].block, &ident);
+
+ if (i == VDS_POS_PRIMARY_VOL_DESC)
+ udf_load_pvoldesc(sb, bh);
+ else if (i == VDS_POS_LOGICAL_VOL_DESC)
+ udf_load_logicalvol(sb, bh, fileset);
+ else if (i == VDS_POS_PARTITION_DESC)
+ {
+ struct buffer_head *bh2 = NULL;
+ udf_load_partdesc(sb, bh);
+ for (j=vds[i].block+1; j<vds[VDS_POS_TERMINATING_DESC].block; j++)
+ {
+ bh2 = udf_read_tagged(sb, j, j, &ident);
+ gd = (struct GenericDesc *)bh2->b_data;
+ if (ident == TID_PARTITION_DESC)
+ udf_load_partdesc(sb, bh2);
+ udf_release_data(bh2);
+ }
+ }
+ udf_release_data(bh);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * udf_check_valid()
+ */
+static int
+udf_check_valid(struct super_block *sb, int novrs, int silent)
+{
+ long block;
+
+ if (novrs)
+ {
+ udf_debug("Validity check skipped because of novrs option\n");
+ return 0;
+ }
+ /* Check that it is NSR02 compliant */
+ /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */
+ else if ((block = udf_vrs(sb, silent)) == -1)
+ {
+ udf_debug("Failed to read byte 32768. Assuming open disc. Skipping validity check\n");
+ return 0;
+ }
+ else
+ return !block;
+}
+
+static int
+udf_load_partition(struct super_block *sb, lb_addr *fileset)
+{
+ struct AnchorVolDescPtr *anchor;
+ Uint16 ident;
+ struct buffer_head *bh;
+ long main_s, main_e, reserve_s, reserve_e;
+ int i;
+
+ if (!sb)
+ return 1;
+
+ for (i=0; i<sizeof(UDF_SB_ANCHOR(sb))/sizeof(int); i++)
+ {
+ if (UDF_SB_ANCHOR(sb)[i] && (bh = udf_read_tagged(sb,
+ UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i] - UDF_SB_SESSION(sb), &ident)))
+ {
+ anchor = (struct AnchorVolDescPtr *)bh->b_data;
+
+ /* Locate the main sequence */
+ main_s = le32_to_cpu( anchor->mainVolDescSeqExt.extLocation );
+ main_e = le32_to_cpu( anchor->mainVolDescSeqExt.extLength );
+ main_e = main_e >> sb->s_blocksize_bits;
+ main_e += main_s;
+
+ /* Locate the reserve sequence */
+ reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation);
+ reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength);
+ reserve_e = reserve_e >> sb->s_blocksize_bits;
+ reserve_e += reserve_s;
+
+ udf_release_data(bh);
+
+ /* Process the main & reserve sequences */
+ /* responsible for finding the PartitionDesc(s) */
+ if (!(udf_process_sequence(sb, main_s, main_e, fileset) &&
+ udf_process_sequence(sb, reserve_s, reserve_e, fileset)))
+ {
+ break;
+ }
+ }
+ }
+
+ if (i == sizeof(UDF_SB_ANCHOR(sb))/sizeof(int))
+ {
+ udf_debug("No Anchor block found\n");
+ return 1;
+ }
+ else
+ udf_debug("Using anchor in block %d\n", UDF_SB_ANCHOR(sb)[i]);
+
+ for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
+ {
+ switch UDF_SB_PARTTYPE(sb, i)
+ {
+ case UDF_VIRTUAL_MAP15:
+ case UDF_VIRTUAL_MAP20:
+ {
+ lb_addr ino;
+
+ if (!UDF_SB_LASTBLOCK(sb))
+ {
+ udf_debug("Unable to determine Lastblock (For Virtual Partition)\n");
+ return 1;
+ }
+
+ if (i == 0)
+ ino.partitionReferenceNum = i+1;
+ else
+ ino.partitionReferenceNum = i-1;
+
+ ino.logicalBlockNum = UDF_SB_LASTBLOCK(sb) - UDF_SB_PARTROOT(sb,ino.partitionReferenceNum);
+
+ if (!(UDF_SB_VAT(sb) = udf_iget(sb, ino)))
+ return 1;
+
+ if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP15)
+ {
+ UDF_SB_TYPEVIRT(sb,i).s_start_offset = UDF_I_EXT0OFFS(UDF_SB_VAT(sb));
+ UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size - 36) / sizeof(Uint32);
+ }
+ else if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP20)
+ {
+ struct buffer_head *bh = NULL;
+ Uint32 pos;
+
+ pos = udf_block_map(UDF_SB_VAT(sb), 0);
+ bh = bread(sb->s_dev, pos, sb->s_blocksize);
+ UDF_SB_TYPEVIRT(sb,i).s_start_offset =
+ le16_to_cpu(((struct VirtualAllocationTable20 *)bh->b_data + UDF_I_EXT0OFFS(UDF_SB_VAT(sb)))->lengthHeader) +
+ UDF_I_EXT0OFFS(UDF_SB_VAT(sb));
+ UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size -
+ UDF_SB_TYPEVIRT(sb,i).s_start_offset) / sizeof(Uint32);
+ udf_release_data(bh);
+ }
+ UDF_SB_PARTROOT(sb,i) = udf_get_pblock(sb, 0, i, 0);
+ UDF_SB_PARTLEN(sb,i) = UDF_SB_PARTLEN(sb,ino.partitionReferenceNum);
+ UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap = 0xFFFFFFFF;
+ }
+ }
+ }
+ return 0;
+}
+
+static void udf_open_lvid(struct super_block *sb)
+{
+#ifdef CONFIG_UDF_RW
+ if (UDF_SB_LVIDBH(sb))
+ {
+ int i;
+ timestamp cpu_time;
+
+ UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
+ UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
+ if (udf_time_to_stamp(&cpu_time, CURRENT_TIME, CURRENT_UTIME))
+ UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time);
+ UDF_SB_LVID(sb)->integrityType = INTEGRITY_TYPE_OPEN;
+
+ UDF_SB_LVID(sb)->descTag.descCRC =
+ cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag),
+ le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0));
+
+ UDF_SB_LVID(sb)->descTag.tagChecksum = 0;
+ for (i=0; i<16; i++)
+ if (i != 4)
+ UDF_SB_LVID(sb)->descTag.tagChecksum +=
+ ((Uint8 *)&(UDF_SB_LVID(sb)->descTag))[i];
+
+ mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+ }
+#endif
+}
+
+static void udf_close_lvid(struct super_block *sb)
+{
+#ifdef CONFIG_UDF_RW
+ if (UDF_SB_LVIDBH(sb) &&
+ UDF_SB_LVID(sb)->integrityType == INTEGRITY_TYPE_OPEN)
+ {
+ int i;
+ timestamp cpu_time;
+
+ UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
+ UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
+ if (udf_time_to_stamp(&cpu_time, CURRENT_TIME, CURRENT_UTIME))
+ UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time);
+
+ UDF_SB_LVID(sb)->integrityType = INTEGRITY_TYPE_CLOSE;
+
+ UDF_SB_LVID(sb)->descTag.descCRC =
+ cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag),
+ le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0));
+
+ UDF_SB_LVID(sb)->descTag.tagChecksum = 0;
+ for (i=0; i<16; i++)
+ if (i != 4)
+ UDF_SB_LVID(sb)->descTag.tagChecksum +=
+ ((Uint8 *)&(UDF_SB_LVID(sb)->descTag))[i];
+
+ mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+ }
+#endif
+}
+
+/*
+ * udf_read_super
+ *
+ * PURPOSE
+ * Complete the specified super block.
+ *
+ * PRE-CONDITIONS
+ * sb Pointer to superblock to complete - never NULL.
+ * sb->s_dev Device to read suberblock from.
+ * options Pointer to mount options.
+ * silent Silent flag.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+static struct super_block *
+udf_read_super(struct super_block *sb, void *options, int silent)
+{
+ struct inode *inode=NULL;
+ struct udf_options uopt;
+ lb_addr rootdir, fileset;
+ int i;
+
+ uopt.flags = 0;
+ uopt.uid = 0;
+ uopt.gid = 0;
+ uopt.umask = 0;
+ uopt.utf8 = 0;
+
+ /* Lock the module in memory (if applicable) */
+ MOD_INC_USE_COUNT;
+
+ lock_super(sb);
+
+ UDF_SB_PARTMAPS(sb) = NULL;
+ UDF_SB_LVIDBH(sb) = NULL;
+ UDF_SB_VAT(sb) = NULL;
+
+ if (!udf_parse_options((char *)options, &uopt))
+ goto error_out;
+
+ memset(UDF_SB_ANCHOR(sb), 0x00, sizeof(UDF_SB_ANCHOR(sb)));
+ fileset.logicalBlockNum = 0xFFFFFFFF;
+ fileset.partitionReferenceNum = 0xFFFF;
+ UDF_SB_RECORDTIME(sb)=0;
+ UDF_SB_VOLIDENT(sb)[0]=0;
+
+ UDF_SB(sb)->s_flags = uopt.flags;
+ UDF_SB(sb)->s_uid = uopt.uid;
+ UDF_SB(sb)->s_gid = uopt.gid;
+ UDF_SB(sb)->s_umask = uopt.umask;
+ UDF_SB(sb)->s_utf8 = uopt.utf8;
+
+ /* Set the block size for all transfers */
+ if (!udf_set_blocksize(sb, uopt.blocksize))
+ goto error_out;
+
+ if ( uopt.session == 0xFFFFFFFF )
+ UDF_SB_SESSION(sb) = udf_get_last_session(sb->s_dev);
+ else
+ UDF_SB_SESSION(sb) = uopt.session;
+
+ udf_debug("Multi-session=%d\n", UDF_SB_SESSION(sb));
+
+ if ( uopt.lastblock == 0xFFFFFFFF )
+ UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb->s_dev, &(UDF_SB(sb)->s_flags));
+ else
+ UDF_SB_LASTBLOCK(sb) = uopt.lastblock;
+
+ UDF_SB_LASTBLOCK(sb) = udf_find_anchor(sb, uopt.anchor, UDF_SB_LASTBLOCK(sb));
+
+ udf_debug("Lastblock=%d\n", UDF_SB_LASTBLOCK(sb));
+
+ if (udf_check_valid(sb, uopt.novrs, silent)) /* read volume recognition sequences */
+ {
+ udf_debug("No VRS found\n");
+ goto error_out;
+ }
+
+ UDF_SB_CHARSET(sb) = NULL;
+
+#ifdef CONFIG_NLS
+ if (uopt.utf8 == 0)
+ {
+ char *p = uopt.iocharset ? uopt.iocharset : "iso8859-1";
+ UDF_SB_CHARSET(sb) = load_nls(p);
+ if (!UDF_SB_CHARSET(sb))
+ if (uopt.iocharset)
+ goto error_out;
+ UDF_SB_CHARSET(sb) = load_nls_default();
+ }
+#endif
+
+ /* Fill in the rest of the superblock */
+ sb->s_op = &udf_sb_ops;
+ sb->s_time = 0;
+ sb->dq_op = NULL;
+ sb->s_dirt = 0;
+ sb->s_magic = UDF_SUPER_MAGIC;
+
+ for (i=0; i<UDF_MAX_BLOCK_LOADED; i++)
+ {
+ UDF_SB_BLOCK_BITMAP_NUMBER(sb,i) = 0;
+ UDF_SB_BLOCK_BITMAP(sb,i) = NULL;
+ }
+ UDF_SB_LOADED_BLOCK_BITMAPS(sb) = 0;
+
+ if (udf_load_partition(sb, &fileset))
+ {
+ udf_debug("No partition found (1)\n");
+ goto error_out;
+ }
+
+ if ( !UDF_SB_NUMPARTS(sb) )
+ {
+ udf_debug("No partition found (2)\n");
+ goto error_out;
+ }
+
+ if ( udf_find_fileset(sb, &fileset, &rootdir) )
+ {
+ udf_debug("No fileset found\n");
+ goto error_out;
+ }
+
+ if (!silent)
+ {
+ timestamp ts;
+ udf_time_to_stamp(&ts, UDF_SB_RECORDTIME(sb), 0);
+ udf_info("Mounting volume '%s', timestamp %u/%02u/%u %02u:%02u\n",
+ UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute);
+ }
+ if (!(sb->s_flags & MS_RDONLY))
+ udf_open_lvid(sb);
+ unlock_super(sb);
+
+ /* Assign the root inode */
+ /* assign inodes by physical block number */
+ /* perhaps it's not extensible enough, but for now ... */
+ inode = udf_iget(sb, rootdir);
+ if (!inode)
+ {
+ udf_debug("Error in udf_iget, block=%d, partition=%d\n",
+ rootdir.logicalBlockNum, rootdir.partitionReferenceNum);
+ goto error_out;
+ }
+
+ /* Allocate a dentry for the root inode */
+ sb->s_root = d_alloc_root(inode);
+ if (!sb->s_root)
+ {
+ iput(inode);
+ udf_debug("Couldn't allocate root dentry\n");
+ goto error_out;
+ }
+
+ return sb;
+
+error_out:
+ sb->s_dev = NODEV;
+ if (UDF_SB_VAT(sb))
+ iput(UDF_SB_VAT(sb));
+ if (!(sb->s_flags & MS_RDONLY))
+ udf_close_lvid(sb);
+ udf_release_data(UDF_SB_LVIDBH(sb));
+ UDF_SB_FREE(sb);
+ unlock_super(sb);
+ MOD_DEC_USE_COUNT;
+ return NULL;
+}
+
+void udf_error(struct super_block *sb, const char *function,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ if (!(sb->s_flags & MS_RDONLY))
+ {
+ /* mark sb error */
+ sb->s_dirt = 1;
+ }
+ va_start(args, fmt);
+ vsprintf(error_buf, fmt, args);
+ va_end(args);
+ printk (KERN_CRIT "UDF-fs error (device %s): %s: %s\n",
+ bdevname(sb->s_dev), function, error_buf);
+}
+
+void udf_warning(struct super_block *sb, const char *function,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ vsprintf(error_buf, fmt, args);
+ va_end(args);
+ printk(KERN_WARNING "UDF-fs warning (device %s): %s: %s\n",
+ bdevname(sb->s_dev), function, error_buf);
+}
+
+/*
+ * udf_put_super
+ *
+ * PURPOSE
+ * Prepare for destruction of the superblock.
+ *
+ * DESCRIPTION
+ * Called before the filesystem is unmounted.
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+static void
+udf_put_super(struct super_block *sb)
+{
+ int i;
+
+ if (UDF_SB_VAT(sb))
+ iput(UDF_SB_VAT(sb));
+ if (!(sb->s_flags & MS_RDONLY))
+ udf_close_lvid(sb);
+ udf_release_data(UDF_SB_LVIDBH(sb));
+ for (i=0; i<UDF_MAX_BLOCK_LOADED; i++)
+ udf_release_data(UDF_SB_BLOCK_BITMAP(sb, i));
+ UDF_SB_FREE(sb);
+
+ MOD_DEC_USE_COUNT;
+}
+
+/*
+ * udf_stat_fs
+ *
+ * PURPOSE
+ * Return info about the filesystem.
+ *
+ * DESCRIPTION
+ * Called by sys_statfs()
+ *
+ * HISTORY
+ * July 1, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+static int
+udf_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
+{
+ int size;
+ struct statfs tmp;
+ int rc;
+
+ size = (bufsize < sizeof(tmp)) ? bufsize: sizeof(tmp);
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.f_type = UDF_SUPER_MAGIC;
+ tmp.f_bsize = sb->s_blocksize;
+ tmp.f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb));
+ tmp.f_bfree = udf_count_free(sb);
+ tmp.f_bavail = tmp.f_bfree;
+ tmp.f_files = (UDF_SB_LVIDBH(sb) ?
+ (le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) +
+ le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + tmp.f_bfree;
+ tmp.f_ffree = tmp.f_bfree;
+ /* __kernel_fsid_t f_fsid */
+ tmp.f_namelen = UDF_NAME_LEN;
+
+ rc= copy_to_user(buf, &tmp, size) ? -EFAULT: 0;
+ return rc;
+}
+
+static unsigned char udf_bitmap_lookup[16] = {
+ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
+};
+
+static unsigned int
+udf_count_free(struct super_block *sb)
+{
+ struct buffer_head *bh = NULL;
+ unsigned int accum=0;
+ int index;
+ int block=0, newblock;
+ lb_addr loc;
+ Uint32 bytes;
+ Uint8 value;
+ Uint8 * ptr;
+ Uint16 ident;
+
+ if (UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace_bitmap == 0xFFFFFFFF)
+ {
+ if (UDF_SB_LVIDBH(sb))
+ {
+ if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb))
+ accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]);
+
+ if (accum == 0xFFFFFFFF)
+ accum = 0;
+
+ return accum;
+ }
+ else
+ return 0;
+ }
+ else
+ {
+ struct SpaceBitmapDesc *bm;
+ loc.logicalBlockNum = UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace_bitmap;
+ loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
+ bh = udf_read_ptagged(sb, loc, 0, &ident);
+
+ if (!bh)
+ {
+ printk(KERN_ERR "udf: udf_count_free failed\n");
+ return 0;
+ }
+ else if (ident != TID_SPACE_BITMAP_DESC)
+ {
+ udf_release_data(bh);
+ printk(KERN_ERR "udf: udf_count_free failed\n");
+ return 0;
+ }
+
+ bm = (struct SpaceBitmapDesc *)bh->b_data;
+ bytes = bm->numOfBytes;
+ index = sizeof(struct SpaceBitmapDesc); /* offset in first block only */
+ ptr = (Uint8 *)bh->b_data;
+
+ while ( bytes > 0 )
+ {
+ while ((bytes > 0) && (index < sb->s_blocksize))
+ {
+ value = ptr[index];
+ accum += udf_bitmap_lookup[ value & 0x0f ];
+ accum += udf_bitmap_lookup[ value >> 4 ];
+ index++;
+ bytes--;
+ }
+ if ( bytes )
+ {
+ udf_release_data(bh);
+ newblock = udf_get_lb_pblock(sb, loc, ++block);
+ bh = udf_tread(sb, newblock, sb->s_blocksize);
+ if (!bh)
+ {
+ udf_debug("read failed\n");
+ return accum;
+ }
+ index = 0;
+ ptr = (Uint8 *)bh->b_data;
+ }
+ }
+ udf_release_data(bh);
+ return accum;
+ }
+}
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
new file mode 100644
index 000000000..0e52198f5
--- /dev/null
+++ b/fs/udf/symlink.c
@@ -0,0 +1,189 @@
+/*
+ * symlink.c
+ *
+ * PURPOSE
+ * Symlink handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ *
+ * (C) 1998-1999 Ben Fennema
+ * (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ * 04/16/99 blf Created.
+ *
+ */
+
+#include "udfdecl.h"
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/udf_fs.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/stat.h>
+#include <linux/malloc.h>
+#include "udf_i.h"
+
+static int udf_readlink(struct dentry *, char *, int);
+static struct dentry * udf_follow_link(struct dentry * dentry,
+ struct dentry * base, unsigned int follow);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations udf_symlink_inode_operations = {
+ NULL, /* no file-operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ udf_readlink, /* readlink */
+ udf_follow_link,/* follow_link */
+ NULL, /* get_block */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* flushpage */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
+};
+
+int udf_pc_to_char(char *from, int fromlen, char **to)
+{
+ struct PathComponent *pc;
+ int elen = 0, len = 0;
+
+ *to = (char *)kmalloc(fromlen, GFP_KERNEL);
+
+ if (!(*to))
+ return -1;
+
+ while (elen < fromlen)
+ {
+ pc = (struct PathComponent *)(from + elen);
+ if (pc->componentType == 1 && pc->lengthComponentIdent == 0)
+ {
+ (*to)[0] = '/';
+ len = 1;
+ }
+ else if (pc->componentType == 3)
+ {
+ memcpy(&(*to)[len], "../", 3);
+ len += 3;
+ }
+ else if (pc->componentType == 4)
+ {
+ memcpy(&(*to)[len], "./", 2);
+ len += 2;
+ }
+ else if (pc->componentType == 5)
+ {
+ memcpy(&(*to)[len], pc->componentIdent, pc->lengthComponentIdent);
+ len += pc->lengthComponentIdent + 1;
+ (*to)[len-1] = '/';
+ }
+ elen += sizeof(struct PathComponent) + pc->lengthComponentIdent;
+ }
+
+ if (len)
+ {
+ len --;
+ (*to)[len] = '\0';
+ }
+ return len;
+}
+
+static struct dentry * udf_follow_link(struct dentry * dentry,
+ struct dentry * base, unsigned int follow)
+{
+ struct inode *inode = dentry->d_inode;
+ struct buffer_head *bh = NULL;
+ char *symlink, *tmpbuf;
+ int len;
+
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+ {
+ bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+
+ if (!bh)
+ return 0;
+
+ symlink = bh->b_data + udf_file_entry_alloc_offset(inode);
+ }
+ else
+ {
+ bh = bread(inode->i_dev, udf_block_map(inode, 0), inode->i_sb->s_blocksize);
+
+ if (!bh)
+ return 0;
+
+ symlink = bh->b_data;
+ }
+
+ if ((len = udf_pc_to_char(symlink, inode->i_size, &tmpbuf)) >= 0)
+ {
+ base = lookup_dentry(tmpbuf, base, follow);
+ kfree(tmpbuf);
+ return base;
+ }
+ else
+ return ERR_PTR(-ENOMEM);
+}
+
+static int udf_readlink(struct dentry * dentry, char * buffer, int buflen)
+{
+ struct inode *inode = dentry->d_inode;
+ struct buffer_head *bh = NULL;
+ char *symlink, *tmpbuf;
+ int len;
+
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+ {
+ bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+
+ if (!bh)
+ return 0;
+
+ symlink = bh->b_data + udf_file_entry_alloc_offset(inode);
+ }
+ else
+ {
+ bh = bread(inode->i_dev, udf_block_map(inode, 0), inode->i_sb->s_blocksize);
+
+ if (!bh)
+ return 0;
+
+ symlink = bh->b_data;
+ }
+
+ if ((len = udf_pc_to_char(symlink, inode->i_size, &tmpbuf)) >= 0)
+ {
+ if (copy_to_user(buffer, tmpbuf, len > buflen ? buflen : len))
+ len = -EFAULT;
+ kfree(tmpbuf);
+ }
+ else
+ len = -ENOMEM;
+
+ UPDATE_ATIME(inode);
+ if (bh)
+ udf_release_data(bh);
+ return len;
+}
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
new file mode 100644
index 000000000..f11ccf7af
--- /dev/null
+++ b/fs/udf/truncate.c
@@ -0,0 +1,229 @@
+/*
+ * truncate.c
+ *
+ * PURPOSE
+ * Truncate handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ *
+ * (C) 1999 Ben Fennema
+ * (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ * 02/24/99 blf Created.
+ *
+ */
+
+#include "udfdecl.h"
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/udf_fs.h>
+
+#include "udf_i.h"
+#include "udf_sb.h"
+
+static void extent_trunc(struct inode * inode, lb_addr bloc, int *extoffset,
+ lb_addr eloc, Uint32 elen, struct buffer_head **bh, Uint32 offset)
+{
+ lb_addr neloc = { 0, 0 };
+ int nelen = 0;
+ int blocks = inode->i_sb->s_blocksize / 512;
+ int last_block = (elen + inode->i_sb->s_blocksize - 1) / inode->i_sb->s_blocksize;
+
+
+ if (offset)
+ {
+ nelen = ((offset - 1) << inode->i_sb->s_blocksize_bits) +
+ (inode->i_size & (inode->i_sb->s_blocksize - 1));
+ neloc = eloc;
+ }
+
+ inode->i_blocks -= (blocks * (last_block - offset));
+ udf_write_aext(inode, bloc, extoffset, neloc, nelen, bh, 1);
+ if (!memcmp(&UDF_I_EXT0LOC(inode), &eloc, sizeof(lb_addr)))
+ {
+ UDF_I_EXT0LOC(inode) = neloc;
+ UDF_I_EXT0LEN(inode) = nelen;
+ }
+ mark_inode_dirty(inode);
+ udf_free_blocks(inode, eloc, offset, last_block - offset);
+}
+
+static void trunc(struct inode * inode)
+{
+ lb_addr bloc, eloc, neloc = { 0, 0 };
+ Uint32 extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc;
+ int etype;
+ int first_block = (inode->i_size + inode->i_sb->s_blocksize - 1) / inode->i_sb->s_blocksize;
+ struct buffer_head *bh = NULL;
+ int adsize;
+
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+ adsize = sizeof(short_ad);
+ else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+ adsize = sizeof(long_ad);
+ else
+ adsize = 0;
+
+ if ((etype = inode_bmap(inode, first_block, &bloc, &extoffset, &eloc, &elen, &offset, &bh)) != -1)
+ {
+ extoffset -= adsize;
+ extent_trunc(inode, bloc, &extoffset, eloc, elen, &bh, offset);
+
+ if (offset)
+ lenalloc = extoffset;
+ else
+ lenalloc = extoffset - adsize;
+
+ if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
+ lenalloc -= udf_file_entry_alloc_offset(inode);
+ else
+ lenalloc -= sizeof(struct AllocExtDesc);
+
+ while ((etype = udf_current_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 0)) != -1)
+ {
+ if (etype == EXTENT_NEXT_EXTENT_ALLOCDECS)
+ {
+ udf_write_aext(inode, bloc, &extoffset, neloc, nelen, &bh, 0);
+ extoffset = 0;
+ if (lelen)
+ {
+ if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
+ memset(bh->b_data, 0x00, udf_file_entry_alloc_offset(inode));
+ else
+ memset(bh->b_data, 0x00, sizeof(struct AllocExtDesc));
+ udf_free_blocks(inode, bloc, 0, lelen);
+ }
+ else
+ {
+ if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
+ UDF_I_LENALLOC(inode) = lenalloc;
+ else
+ {
+ struct AllocExtDesc *aed = (struct AllocExtDesc *)(bh->b_data);
+ aed->lengthAllocDescs = cpu_to_le32(lenalloc);
+ }
+ }
+
+ udf_release_data(bh);
+ bh = NULL;
+
+ bloc = eloc;
+ if (elen)
+ lelen = (elen + inode->i_sb->s_blocksize - 1) >>
+ inode->i_sb->s_blocksize_bits;
+ else
+ lelen = 1;
+ }
+ else if (etype != EXTENT_NOT_RECORDED_NOT_ALLOCATED)
+ extent_trunc(inode, bloc, &extoffset, eloc, elen, &bh, 0);
+ else
+ udf_write_aext(inode, bloc, &extoffset, neloc, nelen, &bh, 1);
+ }
+
+ if (lelen)
+ {
+ if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
+ memset(bh->b_data, 0x00, udf_file_entry_alloc_offset(inode));
+ else
+ memset(bh->b_data, 0x00, sizeof(struct AllocExtDesc));
+ udf_free_blocks(inode, bloc, 0, lelen);
+ }
+ else
+ {
+ if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
+ UDF_I_LENALLOC(inode) = lenalloc;
+ else
+ {
+ struct AllocExtDesc *aed = (struct AllocExtDesc *)(bh->b_data);
+ aed->lengthAllocDescs = cpu_to_le32(lenalloc);
+ }
+ }
+ }
+ else if (inode->i_size)
+ {
+ lb_addr e0loc = UDF_I_LOCATION(inode);
+ Uint32 ext0offset = udf_file_entry_alloc_offset(inode);
+ char tetype;
+
+ if (offset)
+ {
+ extoffset -= adsize;
+ tetype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1);
+ if (tetype == EXTENT_NOT_RECORDED_NOT_ALLOCATED)
+ {
+ extoffset -= adsize;
+ elen = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) |
+ (elen + (offset << inode->i_sb->s_blocksize_bits));
+ if (ext0offset == extoffset && !memcmp(&e0loc, &bloc, sizeof(lb_addr)))
+ UDF_I_EXT0LEN(inode) = elen;
+ udf_write_aext(inode, bloc, &extoffset, eloc, elen, &bh, 0);
+ }
+ else
+ {
+ if (elen & (inode->i_sb->s_blocksize - 1))
+ {
+ extoffset -= adsize;
+ elen = (EXTENT_RECORDED_ALLOCATED << 30) |
+ ((elen + inode->i_sb->s_blocksize - 1) &
+ ~(inode->i_sb->s_blocksize - 1));
+ if (ext0offset == extoffset && !memcmp(&e0loc, &bloc, sizeof(lb_addr)))
+ UDF_I_EXT0LEN(inode) = elen;
+ udf_write_aext(inode, bloc, &extoffset, eloc, elen, &bh, 1);
+ }
+ memset(&eloc, 0x00, sizeof(lb_addr));
+ elen = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) |
+ (offset << inode->i_sb->s_blocksize_bits);
+ if (ext0offset == extoffset && !memcmp(&e0loc, &bloc, sizeof(lb_addr)))
+ {
+ UDF_I_EXT0LOC(inode) = eloc;
+ UDF_I_EXT0LEN(inode) = elen;
+ }
+ udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
+ }
+ }
+ }
+
+ udf_release_data(bh);
+}
+
+void udf_truncate(struct inode * inode)
+{
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)))
+ return;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ return;
+
+ if (!UDF_I_EXT0OFFS(inode))
+ {
+ udf_discard_prealloc(inode);
+
+ trunc(inode);
+ }
+
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+}
+
+void udf_truncate_adinicb(struct inode * inode)
+{
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)))
+ return;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ return;
+
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+}
diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h
new file mode 100644
index 000000000..8b9038296
--- /dev/null
+++ b/fs/udf/udf_i.h
@@ -0,0 +1,24 @@
+#ifndef __LINUX_UDF_I_H
+#define __LINUX_UDF_I_H
+
+#define UDF_I(X) (&((X)->u.udf_i))
+
+#define UDF_I_EXT0LOC(X) ( UDF_I(X)->i_ext0Location )
+#define UDF_I_EXT0LEN(X) ( UDF_I(X)->i_ext0Length )
+#define UDF_I_EXT0OFFS(X) ( UDF_I(X)->i_ext0Offset )
+#define UDF_I_LOCATION(X) ( UDF_I(X)->i_location )
+#define UDF_I_LENEATTR(X) ( UDF_I(X)->i_lenEAttr )
+#define UDF_I_LENALLOC(X) ( UDF_I(X)->i_lenAlloc )
+#define UDF_I_UNIQUE(X) ( UDF_I(X)->i_unique )
+#define UDF_I_ALLOCTYPE(X) ( UDF_I(X)->i_alloc_type )
+#define UDF_I_EXTENDED_FE(X)( UDF_I(X)->i_extended_fe )
+#define UDF_I_STRAT4096(X) ( UDF_I(X)->i_strat_4096 )
+#define UDF_I_PREALLOC_COUNT(X) ( UDF_I(X)->i_prealloc_count )
+#define UDF_I_PREALLOC_BLOCK(X) ( UDF_I(X)->i_prealloc_block )
+#define UDF_I_NEXT_ALLOC_BLOCK(X) ( UDF_I(X)->i_next_alloc_block )
+#define UDF_I_NEXT_ALLOC_GOAL(X) ( UDF_I(X)->i_next_alloc_goal )
+#define UDF_I_UATIME(X) ( UDF_I(X)->i_uatime )
+#define UDF_I_UMTIME(X) ( UDF_I(X)->i_umtime )
+#define UDF_I_UCTIME(X) ( UDF_I(X)->i_uctime )
+
+#endif /* !defined(_LINUX_UDF_I_H) */
diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
new file mode 100644
index 000000000..407d6006d
--- /dev/null
+++ b/fs/udf/udf_sb.h
@@ -0,0 +1,66 @@
+#ifndef __LINUX_UDF_SB_H
+#define __LINUX_UDF_SB_H
+
+#include <linux/udf_167.h>
+#include <linux/udf_udf.h>
+
+/* Since UDF 1.50 is ISO 13346 based... */
+#define UDF_SUPER_MAGIC 0x15013346
+
+#define UDF_FLAG_STRICT 0x00000001U
+#define UDF_FLAG_UNDELETE 0x00000002U
+#define UDF_FLAG_UNHIDE 0x00000004U
+#define UDF_FLAG_VARCONV 0x00000008U
+
+#define UDF_SB_FREE(X)\
+{\
+ if (UDF_SB(X))\
+ {\
+ if (UDF_SB_PARTMAPS(X))\
+ kfree(UDF_SB_PARTMAPS(X));\
+ UDF_SB_PARTMAPS(X) = NULL;\
+ }\
+}
+#define UDF_SB(X) (&((X)->u.udf_sb))
+
+#define UDF_SB_ALLOC_PARTMAPS(X,Y)\
+{\
+ UDF_SB_NUMPARTS(X) = Y;\
+ UDF_SB_PARTMAPS(X) = kmalloc(sizeof(struct udf_part_map) * Y, GFP_KERNEL);\
+}
+
+#define IS_STRICT(X) ( UDF_SB(X)->s_flags & UDF_FLAG_STRICT )
+#define IS_UNDELETE(X) ( UDF_SB(X)->s_flags & UDF_FLAG_UNDELETE )
+#define IS_UNHIDE(X) ( UDF_SB(X)->s_flags & UDF_FLAG_UNHIDE )
+
+#define UDF_SB_SESSION(X) ( UDF_SB(X)->s_session )
+#define UDF_SB_ANCHOR(X) ( UDF_SB(X)->s_anchor )
+#define UDF_SB_NUMPARTS(X) ( UDF_SB(X)->s_partitions )
+#define UDF_SB_VOLUME(X) ( UDF_SB(X)->s_thisvolume )
+#define UDF_SB_LASTBLOCK(X) ( UDF_SB(X)->s_lastblock )
+#define UDF_SB_VOLDESC(X) ( UDF_SB(X)->s_voldesc )
+#define UDF_SB_LVIDBH(X) ( UDF_SB(X)->s_lvidbh )
+#define UDF_SB_LVID(X) ( (struct LogicalVolIntegrityDesc *)UDF_SB_LVIDBH(X)->b_data )
+#define UDF_SB_LVIDIU(X) ( (struct LogicalVolIntegrityDescImpUse *)&(UDF_SB_LVID(sb)->impUse[UDF_SB_LVID(sb)->numOfPartitions * 2 * sizeof(Uint32)/sizeof(Uint8)]) )
+#define UDF_SB_PARTITION(X) ( UDF_SB(X)->s_partition )
+#define UDF_SB_RECORDTIME(X) ( UDF_SB(X)->s_recordtime )
+#define UDF_SB_VOLIDENT(X) ( UDF_SB(X)->s_volident )
+#define UDF_SB_PARTMAPS(X) ( UDF_SB(X)->s_partmaps )
+#define UDF_SB_LOCATION(X) ( UDF_SB(X)->s_location )
+#define UDF_SB_SERIALNUM(X) ( UDF_SB(X)->s_serialnum )
+#define UDF_SB_CHARSET(X) ( UDF_SB(X)->s_nls_iocharset )
+#define UDF_SB_VAT(X) ( UDF_SB(X)->s_vat )
+
+#define UDF_SB_BLOCK_BITMAP_NUMBER(X,Y) ( UDF_SB(X)->s_block_bitmap_number[Y] )
+#define UDF_SB_BLOCK_BITMAP(X,Y) ( UDF_SB(X)->s_block_bitmap[Y] )
+#define UDF_SB_LOADED_BLOCK_BITMAPS(X) ( UDF_SB(X)->s_loaded_block_bitmaps )
+
+#define UDF_SB_PARTTYPE(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_partition_type )
+#define UDF_SB_PARTROOT(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_partition_root )
+#define UDF_SB_PARTLEN(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_partition_len )
+#define UDF_SB_PARTVSN(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_volumeseqnum )
+#define UDF_SB_PARTNUM(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_partition_num )
+#define UDF_SB_TYPESPAR(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_type_specific.s_sparing )
+#define UDF_SB_TYPEVIRT(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_type_specific.s_virtual )
+
+#endif /* __LINUX_UDF_SB_H */
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
new file mode 100644
index 000000000..9ac5999b9
--- /dev/null
+++ b/fs/udf/udfdecl.h
@@ -0,0 +1,278 @@
+#ifndef __UDF_DECL_H
+#define __UDF_DECL_H
+
+#define UDF_VERSION_NOTICE "v0.8.9"
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/udf_udf.h>
+#include <linux/udf_fs.h>
+#include <linux/config.h>
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,7)
+#error "The UDF Module Current Requires Kernel Version 2.3.7 or greater"
+#endif
+
+/* if we're not defined, we must be compiling outside of the kernel tree */
+#if !defined(CONFIG_UDF_FS) && !defined(CONFIG_UDF_FS_MODULE)
+/* ... so override config */
+#define CONFIG_UDF_FS_MODULE
+#include <linux/fs.h>
+/* explicitly include udf_fs_sb.h and udf_fs_i.h */
+#include <linux/udf_fs_sb.h>
+#include <linux/udf_fs_i.h>
+#else
+#include <linux/fs.h> /* also gets udf_fs_i.h and udf_fs_sb.h */
+#endif
+
+struct dentry;
+struct inode;
+struct task_struct;
+struct buffer_head;
+struct super_block;
+
+extern struct inode_operations udf_dir_inode_operations;
+extern struct inode_operations udf_file_inode_operations;
+extern struct inode_operations udf_file_inode_operations_adinicb;
+extern struct inode_operations udf_symlink_inode_operations;
+
+struct udf_fileident_bh
+{
+ struct buffer_head *sbh;
+ struct buffer_head *ebh;
+ int soffset;
+ int eoffset;
+};
+
+extern void udf_error(struct super_block *, const char *, const char *, ...);
+extern void udf_warning(struct super_block *, const char *, const char *, ...);
+extern int udf_write_fi(struct FileIdentDesc *, struct FileIdentDesc *, struct udf_fileident_bh *, Uint8 *, Uint8 *);
+extern struct dentry * udf_lookup(struct inode *, struct dentry *);
+extern int udf_create(struct inode *, struct dentry *, int);
+extern int udf_mknod(struct inode *, struct dentry *, int, int);
+extern int udf_mkdir(struct inode *, struct dentry *, int);
+extern int udf_rmdir(struct inode *, struct dentry *);
+extern int udf_unlink(struct inode *, struct dentry *);
+extern int udf_symlink(struct inode *, struct dentry *, const char *);
+extern int udf_link(struct dentry *, struct inode *, struct dentry *);
+extern int udf_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+extern int udf_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+extern struct inode *udf_iget(struct super_block *, lb_addr);
+extern int udf_sync_inode(struct inode *);
+extern struct buffer_head * udf_expand_adinicb(struct inode *, int *, int, int *);
+extern struct buffer_head * udf_getblk(struct inode *, long, int, int *);
+extern int udf_get_block(struct inode *, long, struct buffer_head *, int);
+extern struct buffer_head * udf_bread(struct inode *, int, int, int *);
+extern void udf_read_inode(struct inode *);
+extern void udf_put_inode(struct inode *);
+extern void udf_delete_inode(struct inode *);
+extern void udf_write_inode(struct inode *);
+extern long udf_locked_block_map(struct inode *, long);
+extern long udf_block_map(struct inode *, long);
+extern int inode_bmap(struct inode *, int, lb_addr *, Uint32 *, lb_addr *, Uint32 *, Uint32 *, struct buffer_head **);
+extern int udf_add_aext(struct inode *, lb_addr *, int *, lb_addr, Uint32, struct buffer_head **, int);
+extern int udf_write_aext(struct inode *, lb_addr, int *, lb_addr, Uint32, struct buffer_head **, int);
+extern int udf_insert_aext(struct inode *, lb_addr, int, lb_addr, Uint32, struct buffer_head *);
+extern int udf_delete_aext(struct inode *, lb_addr, int, lb_addr, Uint32, struct buffer_head *);
+extern int udf_next_aext(struct inode *, lb_addr *, int *, lb_addr *, Uint32 *, struct buffer_head **, int);
+extern int udf_current_aext(struct inode *, lb_addr *, int *, lb_addr *, Uint32 *, struct buffer_head **, int);
+
+extern int udf_read_tagged_data(char *, int size, int fd, int block, int partref);
+
+extern struct buffer_head *udf_tread(struct super_block *, int, int);
+extern struct GenericAttrFormat *udf_add_extendedattr(struct inode *, Uint32, Uint32, Uint8, struct buffer_head **);
+extern struct GenericAttrFormat *udf_get_extendedattr(struct inode *, Uint32, Uint8, struct buffer_head **);
+extern struct buffer_head *udf_read_tagged(struct super_block *, Uint32, Uint32, Uint16 *);
+extern struct buffer_head *udf_read_ptagged(struct super_block *, lb_addr, Uint32, Uint16 *);
+extern struct buffer_head *udf_read_untagged(struct super_block *, Uint32, Uint32);
+extern void udf_release_data(struct buffer_head *);
+
+extern unsigned int udf_get_last_session(kdev_t);
+extern unsigned int udf_get_last_block(kdev_t, int *);
+
+extern Uint32 udf_get_pblock(struct super_block *, Uint32, Uint16, Uint32);
+extern Uint32 udf_get_lb_pblock(struct super_block *, lb_addr, Uint32);
+
+extern int udf_get_filename(Uint8 *, Uint8 *, int);
+
+extern void udf_free_inode(struct inode *);
+extern struct inode * udf_new_inode (const struct inode *, int, int *);
+extern void udf_discard_prealloc(struct inode *);
+extern void udf_truncate(struct inode *);
+extern void udf_truncate_adinicb(struct inode *);
+extern void udf_free_blocks(const struct inode *, lb_addr, Uint32, Uint32);
+extern int udf_alloc_blocks(const struct inode *, Uint16, Uint32, Uint32);
+extern int udf_new_block(const struct inode *, Uint16, Uint32, int *);
+extern int udf_sync_file(struct file *, struct dentry *);
+
+#else
+
+#include <sys/types.h>
+#include <linux/udf_udf.h>
+
+#endif /* __KERNEL__ */
+
+#include "udfend.h"
+
+/* structures */
+struct udf_directory_record
+{
+ Uint32 d_parent;
+ Uint32 d_inode;
+ Uint32 d_name[255];
+};
+
+#define VDS_POS_PRIMARY_VOL_DESC 0
+#define VDS_POS_UNALLOC_SPACE_DESC 1
+#define VDS_POS_LOGICAL_VOL_DESC 2
+#define VDS_POS_PARTITION_DESC 3
+#define VDS_POS_IMP_USE_VOL_DESC 4
+#define VDS_POS_VOL_DESC_PTR 5
+#define VDS_POS_TERMINATING_DESC 6
+#define VDS_POS_LENGTH 7
+
+struct udf_vds_record
+{
+ Uint32 block;
+ Uint32 volDescSeqNum;
+};
+
+struct ktm
+{
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_isdst;
+};
+
+struct ustr
+{
+ Uint8 u_cmpID;
+ Uint8 u_name[UDF_NAME_LEN-1];
+ Uint8 u_len;
+ Uint8 padding;
+ unsigned long u_hash;
+};
+
+
+#define udf_fixed_to_variable(x) ( ( ( (x) >> 5 ) * 39 ) + ( (x) & 0x0000001F ) )
+#define udf_variable_to_fixed(x) ( ( ( (x) / 39 ) << 5 ) + ( (x) % 39 ) )
+
+#ifdef __KERNEL__
+
+#define CURRENT_UTIME (xtime.tv_usec)
+
+#define udf_file_entry_alloc_offset(inode)\
+ ((UDF_I_EXTENDED_FE(inode) ?\
+ sizeof(struct ExtendedFileEntry) :\
+ sizeof(struct FileEntry)) + UDF_I_LENEATTR(inode))
+
+#define udf_clear_bit(nr,addr) ext2_clear_bit(nr,addr)
+#define udf_set_bit(nr,addr) ext2_set_bit(nr,addr)
+#define udf_test_bit(nr, addr) ext2_test_bit(nr, addr)
+#define udf_find_first_one_bit(addr, size) find_first_one_bit(addr, size)
+#define udf_find_next_one_bit(addr, size, offset) find_next_one_bit(addr, size, offset)
+
+#define leBPL_to_cpup(x) leNUM_to_cpup(BITS_PER_LONG, x)
+#define leNUM_to_cpup(x,y) xleNUM_to_cpup(x,y)
+#define xleNUM_to_cpup(x,y) (le ## x ## _to_cpup(y))
+
+extern inline int find_next_one_bit (void * addr, int size, int offset)
+{
+ unsigned long * p = ((unsigned long *) addr) + (offset / BITS_PER_LONG);
+ unsigned long result = offset & ~(BITS_PER_LONG-1);
+ unsigned long tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset &= (BITS_PER_LONG-1);
+ if (offset)
+ {
+ tmp = leBPL_to_cpup(p++);
+ tmp &= ~0UL << offset;
+ if (size < BITS_PER_LONG)
+ goto found_first;
+ if (tmp)
+ goto found_middle;
+ size -= BITS_PER_LONG;
+ result += BITS_PER_LONG;
+ }
+ while (size & ~(BITS_PER_LONG-1))
+ {
+ if ((tmp = leBPL_to_cpup(p++)))
+ goto found_middle;
+ result += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
+ }
+ if (!size)
+ return result;
+ tmp = leBPL_to_cpup(p);
+found_first:
+ tmp &= ~0UL >> (BITS_PER_LONG-size);
+found_middle:
+ return result + ffz(~tmp);
+}
+
+#define find_first_one_bit(addr, size)\
+ find_next_one_bit((addr), (size), 0)
+
+#endif
+
+/* Miscellaneous UDF Prototypes */
+
+extern int udf_ustr_to_dchars(Uint8 *, const struct ustr *, int);
+extern int udf_ustr_to_char(Uint8 *, const struct ustr *, int);
+extern int udf_ustr_to_dstring(dstring *, const struct ustr *, int);
+extern int udf_dchars_to_ustr(struct ustr *, const Uint8 *, int);
+extern int udf_char_to_ustr(struct ustr *, const Uint8 *, int);
+extern int udf_dstring_to_ustr(struct ustr *, const dstring *, int);
+
+extern Uint16 udf_crc(Uint8 *, Uint32, Uint16);
+extern int udf_translate_to_linux(Uint8 *, Uint8 *, int, Uint8 *, int);
+extern int udf_build_ustr(struct ustr *, dstring *, int);
+extern int udf_build_ustr_exact(struct ustr *, dstring *, int);
+extern int udf_CS0toUTF8(struct ustr *, struct ustr *);
+extern int udf_UTF8toCS0(dstring *, struct ustr *, int);
+
+extern uid_t udf_convert_uid(int);
+extern gid_t udf_convert_gid(int);
+extern Uint32 udf64_low32(Uint64);
+extern Uint32 udf64_high32(Uint64);
+
+
+extern time_t *udf_stamp_to_time(time_t *, timestamp);
+extern timestamp *udf_time_to_stamp(timestamp *, time_t, long);
+extern time_t udf_converttime (struct ktm *);
+
+#ifdef __KERNEL__
+extern Uint8 *
+udf_filead_read(struct inode *, Uint8 *, Uint8, lb_addr, int *, int *,
+ struct buffer_head **, int *);
+
+extern struct FileIdentDesc *
+udf_fileident_read(struct inode *, int *,
+ struct udf_fileident_bh *,
+ struct FileIdentDesc *,
+ lb_addr *, Uint32 *,
+ Uint32 *, struct buffer_head **);
+#endif
+extern struct FileIdentDesc *
+udf_get_fileident(void * buffer, int bufsize, int * offset);
+extern extent_ad * udf_get_fileextent(void * buffer, int bufsize, int * offset);
+extern long_ad * udf_get_filelongad(void * buffer, int bufsize, int * offset, int);
+extern short_ad * udf_get_fileshortad(void * buffer, int bufsize, int * offset, int);
+extern Uint8 * udf_get_filead(struct FileEntry *, Uint8 *, int, int, int, int *);
+
+extern void udf_update_tag(char *, int);
+extern void udf_new_tag(char *, Uint16, Uint16, Uint16, Uint32, int);
+
+#endif
diff --git a/fs/udf/udfend.h b/fs/udf/udfend.h
new file mode 100644
index 000000000..906a619bc
--- /dev/null
+++ b/fs/udf/udfend.h
@@ -0,0 +1,111 @@
+#ifndef __UDF_ENDIAN_H
+#define __UDF_ENDIAN_H
+
+#ifndef __KERNEL__
+
+#if __BYTE_ORDER == 0
+
+#error "__BYTE_ORDER must be defined"
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+#define le16_to_cpu(x) \
+ ((Uint16)((((Uint16)(x) & 0x00FFU) << 8) | \
+ (((Uint16)(x) & 0xFF00U) >> 8)))
+
+#define le32_to_cpu(x) \
+ ((Uint32)((((Uint32)(x) & 0x000000FFU) << 24) | \
+ (((Uint32)(x) & 0x0000FF00U) << 8) | \
+ (((Uint32)(x) & 0x00FF0000U) >> 8) | \
+ (((Uint32)(x) & 0xFF000000U) >> 24)))
+
+#define le64_to_cpu(x) \
+ ((Uint64)((((Uint64)(x) & 0x00000000000000FFULL) << 56) | \
+ (((Uint64)(x) & 0x000000000000FF00ULL) << 40) | \
+ (((Uint64)(x) & 0x0000000000FF0000ULL) << 24) | \
+ (((Uint64)(x) & 0x00000000FF000000ULL) << 8) | \
+ (((Uint64)(x) & 0x000000FF00000000ULL) >> 8) | \
+ (((Uint64)(x) & 0x0000FF0000000000ULL) >> 24) | \
+ (((Uint64)(x) & 0x00FF000000000000ULL) >> 40) | \
+ (((Uint64)(x) & 0xFF00000000000000ULL) >> 56)))
+
+#define cpu_to_le16(x) (le16_to_cpu(x))
+#define cpu_to_le32(x) (le32_to_cpu(x))
+#define cpu_to_le64(x) (le64_to_cpu(x))
+
+#else /* __BYTE_ORDER == __LITTLE_ENDIAN */
+
+#define le16_to_cpu(x) (x)
+#define le32_to_cpu(x) (x)
+#define le64_to_cpu(x) (x)
+#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_le64(x) (x)
+
+#endif
+
+#endif
+
+#ifdef __KERNEL__
+#include <linux/string.h>
+#endif
+
+static inline lb_addr lelb_to_cpu(lb_addr in)
+{
+ lb_addr out;
+ out.logicalBlockNum = le32_to_cpu(in.logicalBlockNum);
+ out.partitionReferenceNum = le16_to_cpu(in.partitionReferenceNum);
+ return out;
+}
+
+static inline lb_addr cpu_to_lelb(lb_addr in)
+{
+ lb_addr out;
+ out.logicalBlockNum = cpu_to_le32(in.logicalBlockNum);
+ out.partitionReferenceNum = cpu_to_le16(in.partitionReferenceNum);
+ return out;
+}
+
+static inline timestamp lets_to_cpu(timestamp in)
+{
+ timestamp out;
+ memcpy(&out, &in, sizeof(timestamp));
+ out.typeAndTimezone = le16_to_cpu(in.typeAndTimezone);
+ out.year = le16_to_cpu(in.year);
+ return out;
+}
+
+static inline long_ad lela_to_cpu(long_ad in)
+{
+ long_ad out;
+ out.extLength = le32_to_cpu(in.extLength);
+ out.extLocation = lelb_to_cpu(in.extLocation);
+ return out;
+}
+
+static inline long_ad cpu_to_lela(long_ad in)
+{
+ long_ad out;
+ out.extLength = cpu_to_le32(in.extLength);
+ out.extLocation = cpu_to_lelb(in.extLocation);
+ return out;
+}
+
+static inline extent_ad leea_to_cpu(extent_ad in)
+{
+ extent_ad out;
+ out.extLength = le32_to_cpu(in.extLength);
+ out.extLocation = le32_to_cpu(in.extLocation);
+ return out;
+}
+
+static inline timestamp cpu_to_lets(timestamp in)
+{
+ timestamp out;
+ memcpy(&out, &in, sizeof(timestamp));
+ out.typeAndTimezone = cpu_to_le16(in.typeAndTimezone);
+ out.year = cpu_to_le16(in.year);
+ return out;
+}
+
+#endif /* __UDF_ENDIAN_H */
diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c
new file mode 100644
index 000000000..715fdb4bc
--- /dev/null
+++ b/fs/udf/udftime.c
@@ -0,0 +1,373 @@
+/* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Paul Eggert (eggert@twinsun.com).
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/*
+ * dgb 10/2/98: ripped this from glibc source to help convert timestamps to unix time
+ * 10/4/98: added new table-based lookup after seeing how ugly the gnu code is
+ */
+
+/* Assume that leap seconds are possible, unless told otherwise.
+ If the host has a `zic' command with a `-L leapsecondfilename' option,
+ then it supports leap seconds; otherwise it probably doesn't. */
+#ifndef LEAP_SECONDS_POSSIBLE
+#define LEAP_SECONDS_POSSIBLE 1
+#endif
+
+#if defined(__linux__) && defined(__KERNEL__)
+#include <linux/types.h>
+#include <linux/kernel.h>
+#else
+#include <stdio.h>
+#include <sys/types.h>
+#endif
+
+#include "udfdecl.h"
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#ifndef INT_MIN
+#define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
+#endif
+#ifndef INT_MAX
+#define INT_MAX (~0 - INT_MIN)
+#endif
+
+#ifndef TIME_T_MIN
+#define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
+ : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
+#endif
+#ifndef TIME_T_MAX
+#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
+#endif
+
+#define TM_YEAR_BASE 1900
+#define EPOCH_YEAR 1970
+
+#ifndef __isleap
+/* Nonzero if YEAR is a leap year (every 4 years,
+ except every 100th isn't, and every 400th is). */
+#define __isleap(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+#endif
+
+/* How many days come before each month (0-12). */
+const unsigned short int __mon_yday[2][13] =
+ {
+ /* Normal years. */
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ /* Leap years. */
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+ };
+
+time_t udf_converttime (struct ktm *);
+#ifndef USE_GNU_MKTIME_METHOD
+
+#define MAX_YEAR_SECONDS 68
+
+time_t year_seconds[MAX_YEAR_SECONDS]= {
+ 0,
+ /*1971:*/ 31554000, /*1972:*/ 63090000, /*1973:*/ 94712400,
+ /*1974:*/ 126248400, /*1975:*/ 157784400, /*1976:*/ 189320400,
+ /*1977:*/ 220942800, /*1978:*/ 252478800, /*1979:*/ 284014800,
+ /*1980:*/ 315550800, /*1981:*/ 347173200, /*1982:*/ 378709200,
+ /*1983:*/ 410245200, /*1984:*/ 441781200, /*1985:*/ 473403600,
+ /*1986:*/ 504939600, /*1987:*/ 536475600, /*1988:*/ 568011600,
+ /*1989:*/ 599634000, /*1990:*/ 631170000, /*1991:*/ 662706000,
+ /*1992:*/ 694242000, /*1993:*/ 725864400, /*1994:*/ 757400400,
+ /*1995:*/ 788936400, /*1996:*/ 820472400, /*1997:*/ 852094800,
+ /*1998:*/ 883630800, /*1999:*/ 915166800, /*2000:*/ 946702800,
+ /*2001:*/ 978325200, /*2002:*/ 1009861200, /*2003:*/ 1041397200,
+ /*2004:*/ 1072933200, /*2005:*/ 1104555600, /*2006:*/ 1136091600,
+ /*2007:*/ 1167627600, /*2008:*/ 1199163600, /*2009:*/ 1230786000,
+ /*2010:*/ 1262322000, /*2011:*/ 1293858000, /*2012:*/ 1325394000,
+ /*2013:*/ 1357016400, /*2014:*/ 1388552400, /*2015:*/ 1420088400,
+ /*2016:*/ 1451624400, /*2017:*/ 1483246800, /*2018:*/ 1514782800,
+ /*2019:*/ 1546318800, /*2020:*/ 1577854800, /*2021:*/ 1609477200,
+ /*2022:*/ 1641013200, /*2023:*/ 1672549200, /*2024:*/ 1704085200,
+ /*2025:*/ 1735707600, /*2026:*/ 1767243600, /*2027:*/ 1798779600,
+ /*2028:*/ 1830315600, /*2029:*/ 1861938000, /*2030:*/ 1893474000,
+ /*2031:*/ 1925010000, /*2032:*/ 1956546000, /*2033:*/ 1988168400,
+ /*2034:*/ 2019704400, /*2035:*/ 2051240400, /*2036:*/ 2082776400,
+ /*2037:*/ 2114398800
+};
+
+time_t udf_converttime (struct ktm *tm)
+{
+ time_t r;
+ int yday;
+
+ if ( !tm )
+ return -1;
+ if ( (tm->tm_year+TM_YEAR_BASE < EPOCH_YEAR) ||
+ (tm->tm_year+TM_YEAR_BASE > EPOCH_YEAR+MAX_YEAR_SECONDS) )
+ return -1;
+ r = year_seconds[tm->tm_year-70];
+
+ yday = ((__mon_yday[__isleap (tm->tm_year + TM_YEAR_BASE)]
+ [tm->tm_mon-1])
+ + tm->tm_mday - 1);
+ r += ( ( (yday* 24) + (tm->tm_hour-1) ) * 60 + tm->tm_min ) * 60 + tm->tm_sec;
+ return r;
+}
+
+#ifdef __KERNEL__
+
+extern struct timezone sys_tz;
+
+#define SECS_PER_HOUR (60 * 60)
+#define SECS_PER_DAY (SECS_PER_HOUR * 24)
+
+timestamp *
+udf_time_to_stamp(timestamp *dest, time_t tv_sec, long tv_usec)
+{
+ long int days, rem, y;
+ const unsigned short int *ip;
+ int offset = (-sys_tz.tz_minuteswest + (sys_tz.tz_dsttime ? 60 : 0));
+
+ if (!dest)
+ return NULL;
+
+ dest->typeAndTimezone = 0x1000 | (offset & 0x0FFF);
+
+ tv_sec += offset * 60;
+ days = tv_sec / SECS_PER_DAY;
+ rem = tv_sec % SECS_PER_DAY;
+ dest->hour = rem / SECS_PER_HOUR;
+ rem %= SECS_PER_HOUR;
+ dest->minute = rem / 60;
+ dest->second = rem % 60;
+ y = 1970;
+
+#define DIV(a,b) ((a) / (b) - ((a) % (b) < 0))
+#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
+
+ while (days < 0 || days >= (__isleap(y) ? 366 : 365))
+ {
+ long int yg = y + days / 365 - (days % 365 < 0);
+
+ /* Adjust DAYS and Y to match the guessed year. */
+ days -= ((yg - y) * 365
+ + LEAPS_THRU_END_OF (yg - 1)
+ - LEAPS_THRU_END_OF (y - 1));
+ y = yg;
+ }
+ dest->year = y;
+ ip = __mon_yday[__isleap(y)];
+ for (y = 11; days < (long int) ip[y]; --y)
+ continue;
+ days -= ip[y];
+ dest->month = y + 1;
+ dest->day = days + 1;
+
+ dest->centiseconds = tv_usec / 10000;
+ dest->hundredsOfMicroseconds = (tv_usec - dest->centiseconds * 10000) / 100;
+ dest->microseconds = (tv_usec - dest->centiseconds * 10000 -
+ dest->hundredsOfMicroseconds * 100);
+ return dest;
+}
+#endif
+
+#else
+
+static time_t ydhms_tm_diff (int, int, int, int, int, const struct ktm *);
+
+
+/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
+ measured in seconds, ignoring leap seconds.
+ YEAR uses the same numbering as TM->tm_year.
+ All values are in range, except possibly YEAR.
+ If overflow occurs, yield the low order bits of the correct answer. */
+static time_t
+ydhms_tm_diff (int year, int yday, int hour, int min, int sec, const struct ktm *tp)
+{
+ time_t result;
+
+ /* Compute intervening leap days correctly even if year is negative.
+ Take care to avoid int overflow. time_t overflow is OK, since
+ only the low order bits of the correct time_t answer are needed.
+ Don't convert to time_t until after all divisions are done, since
+ time_t might be unsigned. */
+ int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
+ int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
+ int a100 = a4 / 25 - (a4 % 25 < 0);
+ int b100 = b4 / 25 - (b4 % 25 < 0);
+ int a400 = a100 >> 2;
+ int b400 = b100 >> 2;
+ int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+ time_t years = year - (time_t) tp->tm_year;
+ time_t days = (365 * years + intervening_leap_days);
+ result= (60 * (60 * (24 * days + (hour - tp->tm_hour))
+ + (min - tp->tm_min))
+ + (sec - tp->tm_sec));
+#ifdef __KERNEL__
+ printk(KERN_ERR "udf: ydhms_tm_diff(%d,%d,%d,%d,%d,) returning %ld\n",
+ year, yday, hour, min, sec, result);
+#endif
+ return result;
+}
+
+
+/* Convert *TP to a time_t value, inverting
+ the monotonic and mostly-unit-linear conversion function CONVERT.
+ Use *OFFSET to keep track of a guess at the offset of the result,
+ compared to what the result would be for UTC without leap seconds.
+ If *OFFSET's guess is correct, only one CONVERT call is needed. */
+time_t
+udf_converttime (struct ktm *tp)
+{
+ time_t t, dt, t0;
+ struct ktm tm;
+
+ /* The maximum number of probes (calls to CONVERT) should be enough
+ to handle any combinations of time zone rule changes, solar time,
+ and leap seconds. Posix.1 prohibits leap seconds, but some hosts
+ have them anyway. */
+ int remaining_probes = 4;
+
+ /* Time requested. Copy it in case CONVERT modifies *TP; this can
+ occur if TP is localtime's returned value and CONVERT is localtime. */
+ int sec = tp->tm_sec;
+ int min = tp->tm_min;
+ int hour = tp->tm_hour;
+ int mday = tp->tm_mday;
+ int mon = tp->tm_mon;
+ int year_requested = tp->tm_year;
+ int isdst = tp->tm_isdst;
+
+ /* Ensure that mon is in range, and set year accordingly. */
+ int mon_remainder = mon % 12;
+ int negative_mon_remainder = mon_remainder < 0;
+ int mon_years = mon / 12 - negative_mon_remainder;
+ int year = year_requested + mon_years;
+
+ /* The other values need not be in range:
+ the remaining code handles minor overflows correctly,
+ assuming int and time_t arithmetic wraps around.
+ Major overflows are caught at the end. */
+
+ /* Calculate day of year from year, month, and day of month.
+ The result need not be in range. */
+ int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
+ [mon_remainder + 12 * negative_mon_remainder])
+ + mday - 1);
+
+#if LEAP_SECONDS_POSSIBLE
+ /* Handle out-of-range seconds specially,
+ since ydhms_tm_diff assumes every minute has 60 seconds. */
+ int sec_requested = sec;
+ if (sec < 0)
+ sec = 0;
+ if (59 < sec)
+ sec = 59;
+#endif
+
+ /* Invert CONVERT by probing. First assume the same offset as last time.
+ Then repeatedly use the error to improve the guess. */
+
+ tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
+ tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+ /*
+ t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
+
+ for (t = t0;
+ (dt = ydhms_tm_diff (year, yday, hour, min, sec, &tm));
+ t += dt)
+ if (--remaining_probes == 0)
+ return -1;
+ */
+
+ /* Check whether tm.tm_isdst has the requested value, if any. */
+ if (0 <= isdst && 0 <= tm.tm_isdst)
+ {
+ int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
+ if (dst_diff)
+ {
+ /* Move two hours in the direction indicated by the disagreement,
+ probe some more, and switch to a new time if found.
+ The largest known fallback due to daylight savings is two hours:
+ once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
+ time_t ot = t - 2 * 60 * 60 * dst_diff;
+ while (--remaining_probes != 0)
+ {
+ struct ktm otm;
+ if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
+ &otm)))
+ {
+ t = ot;
+ tm = otm;
+ break;
+ }
+ if ((ot += dt) == t)
+ break; /* Avoid a redundant probe. */
+ }
+ }
+ }
+
+
+#if LEAP_SECONDS_POSSIBLE
+ if (sec_requested != tm.tm_sec)
+ {
+ /* Adjust time to reflect the tm_sec requested, not the normalized value.
+ Also, repair any damage from a false match due to a leap second. */
+ t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
+ }
+#endif
+
+ if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
+ {
+ /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
+ so check for major overflows. A gross check suffices,
+ since if t has overflowed, it is off by a multiple of
+ TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
+ the difference that is bounded by a small value. */
+
+ double dyear = (double) year_requested + mon_years - tm.tm_year;
+ double dday = 366 * dyear + mday;
+ double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
+
+ if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
+ return -1;
+ }
+
+ *tp = tm;
+#ifdef __KERNEL__
+ udf_debug("returning %ld\n", t);
+#endif
+ return t;
+}
+#endif
+
+#ifdef INCLUDE_PRINT_KTM
+static void
+print_ktm (struct ktm *tp)
+{
+#ifdef __KERNEL__
+ udf_debug(
+#else
+ printf(
+#endif
+ "%04d-%02d-%02d %02d:%02d:%02d isdst %d",
+ tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec, tp->tm_isdst);
+}
+#endif
+
+/* EOF */
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
new file mode 100644
index 000000000..6cf63164d
--- /dev/null
+++ b/fs/udf/unicode.c
@@ -0,0 +1,447 @@
+/*
+ * unicode.c
+ *
+ * PURPOSE
+ * Routines for converting between UTF-8 and OSTA Compressed Unicode.
+ * Also handles filename mangling
+ *
+ * DESCRIPTION
+ * OSTA Compressed Unicode is explained in the OSTA UDF specification.
+ * http://www.osta.org/
+ * UTF-8 is explained in the IETF RFC XXXX.
+ * ftp://ftp.internic.net/rfc/rfcxxxx.txt
+ *
+ * CONTACTS
+ * E-mail regarding any portion of the Linux UDF file system should be
+ * directed to the development team's mailing list (run by majordomo):
+ * linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ * This file is distributed under the terms of the GNU General Public
+ * License (GPL). Copies of the GPL can be obtained from:
+ * ftp://prep.ai.mit.edu/pub/gnu/GPL
+ * Each contributing author retains all rights to their own work.
+ */
+
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/string.h> /* for memset */
+#include <linux/udf_fs.h>
+#else
+#include <string.h>
+#endif
+
+#include "udfdecl.h"
+
+int udf_ustr_to_dchars(Uint8 *dest, const struct ustr *src, int strlen)
+{
+ if ( (!dest) || (!src) || (!strlen) || (src->u_len > strlen) )
+ return 0;
+ memcpy(dest+1, src->u_name, src->u_len-1);
+ dest[0] = src->u_cmpID;
+ return src->u_len;
+}
+
+int udf_ustr_to_char(Uint8 *dest, const struct ustr *src, int strlen)
+{
+ if ( (!dest) || (!src) || (!strlen) || (src->u_len >= strlen) )
+ return 0;
+ memcpy(dest, src->u_name, src->u_len-1);
+ return src->u_len - 1;
+}
+
+int udf_ustr_to_dstring(dstring *dest, const struct ustr *src, int dlength)
+{
+ if ( udf_ustr_to_dchars(dest, src, dlength-1) )
+ {
+ dest[dlength-1] = src->u_len;
+ return dlength;
+ }
+ else
+ return 0;
+}
+
+int udf_dchars_to_ustr(struct ustr *dest, const Uint8 *src, int strlen)
+{
+ if ( (!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN) )
+ return 0;
+ memset(dest, 0, sizeof(struct ustr));
+ memcpy(dest->u_name, src+1, strlen-1);
+ dest->u_cmpID = src[0];
+ dest->u_len = strlen;
+ return strlen;
+}
+
+int udf_char_to_ustr(struct ustr *dest, const Uint8 *src, int strlen)
+{
+ if ( (!dest) || (!src) || (!strlen) || (strlen >= UDF_NAME_LEN) )
+ return 0;
+ memset(dest, 0, sizeof(struct ustr));
+ memcpy(dest->u_name, src, strlen);
+ dest->u_cmpID = 0x08;
+ dest->u_len = strlen + 1;
+ return strlen + 1;
+}
+
+
+int udf_dstring_to_ustr(struct ustr *dest, const dstring *src, int dlength)
+{
+ if ( dlength && udf_dchars_to_ustr(dest, src, src[dlength-1]) )
+ return dlength;
+ else
+ return 0;
+}
+
+/*
+ * udf_build_ustr
+ */
+int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
+{
+ int usesize;
+
+ if ( (!dest) || (!ptr) || (!size) )
+ return -1;
+
+ memset(dest, 0, sizeof(struct ustr));
+ usesize= (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size;
+ dest->u_cmpID=ptr[0];
+ dest->u_len=ptr[size-1];
+ memcpy(dest->u_name, ptr+1, usesize-1);
+ return 0;
+}
+
+/*
+ * udf_build_ustr_exact
+ */
+int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
+{
+ if ( (!dest) || (!ptr) || (!exactsize) )
+ return -1;
+
+ memset(dest, 0, sizeof(struct ustr));
+ dest->u_cmpID=ptr[0];
+ dest->u_len=exactsize-1;
+ memcpy(dest->u_name, ptr+1, exactsize-1);
+ return 0;
+}
+
+/*
+ * udf_ocu_to_udf8
+ *
+ * PURPOSE
+ * Convert OSTA Compressed Unicode to the UTF-8 equivalent.
+ *
+ * DESCRIPTION
+ * This routine is only called by udf_filldir().
+ *
+ * PRE-CONDITIONS
+ * utf Pointer to UTF-8 output buffer.
+ * ocu Pointer to OSTA Compressed Unicode input buffer
+ * of size UDF_NAME_LEN bytes.
+ * both of type "struct ustr *"
+ *
+ * POST-CONDITIONS
+ * <return> Zero on success.
+ *
+ * HISTORY
+ * November 12, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i)
+{
+ Uint8 *ocu;
+ Uint32 c;
+ Uint8 cmp_id, ocu_len;
+ int i;
+
+ ocu = ocu_i->u_name;
+
+ ocu_len = ocu_i->u_len;
+ cmp_id = ocu_i->u_cmpID;
+ utf_o->u_len = 0;
+
+ if (ocu_len == 0)
+ {
+ memset(utf_o, 0, sizeof(struct ustr));
+ utf_o->u_cmpID = 0;
+ utf_o->u_len = 0;
+ return 0;
+ }
+
+ if ((cmp_id != 8) && (cmp_id != 16))
+ {
+#ifdef __KERNEL__
+ printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name);
+#endif
+ return 0;
+ }
+
+ for (i = 0; (i < ocu_len) && (utf_o->u_len < UDF_NAME_LEN) ;) {
+
+ /* Expand OSTA compressed Unicode to Unicode */
+ c = ocu[i++];
+ if (cmp_id == 16)
+ {
+ c = (c << 8) | ocu[i++];
+#ifdef __KERNEL__
+ if (c & 0xFF00)
+ udf_debug("cmd_id == 16 (0x%2x%2x)\n",
+ ((c >> 8) & 0xFF), (c & 0xFF));
+#endif
+ }
+
+ /* Compress Unicode to UTF-8 */
+ if (c < 0x80U)
+ utf_o->u_name[utf_o->u_len++] = (Uint8)c;
+ else if (c < 0x800U) {
+ utf_o->u_name[utf_o->u_len++] = (Uint8)(0xc0 | (c >> 6));
+ utf_o->u_name[utf_o->u_len++] = (Uint8)(0x80 | (c & 0x3f));
+#ifdef __KERNEL__
+ udf_debug("(0x%2x%2x) -> (%2x) (%2x)\n",
+ ((c >> 8) & 0xFF), (c & 0xFF),
+ utf_o->u_name[utf_o->u_len-2],
+ utf_o->u_name[utf_o->u_len-1]);
+#endif
+ } else {
+ utf_o->u_name[utf_o->u_len++] = (Uint8)(0xe0 | (c >> 12));
+ utf_o->u_name[utf_o->u_len++] = (Uint8)(0x80 | ((c >> 6) & 0x3f));
+ utf_o->u_name[utf_o->u_len++] = (Uint8)(0x80 | (c & 0x3f));
+#ifdef __KERNEL__
+ udf_debug("(0x%2x%2x) -> (%2x) (%2x) (%2x)\n",
+ ((c >> 8) & 0xFF), (c & 0xFF),
+ utf_o->u_name[utf_o->u_len-3],
+ utf_o->u_name[utf_o->u_len-2],
+ utf_o->u_name[utf_o->u_len-1]);
+#endif
+ }
+ }
+ utf_o->u_cmpID=8;
+ utf_o->u_hash=0L;
+ utf_o->padding=0;
+
+ return utf_o->u_len;
+}
+
+/*
+ *
+ * udf_utf8_to_ocu
+ *
+ * PURPOSE
+ * Convert UTF-8 to the OSTA Compressed Unicode equivalent.
+ *
+ * DESCRIPTION
+ * This routine is only called by udf_lookup().
+ *
+ * PRE-CONDITIONS
+ * ocu Pointer to OSTA Compressed Unicode output
+ * buffer of size UDF_NAME_LEN bytes.
+ * utf Pointer to UTF-8 input buffer.
+ * utf_len Length of UTF-8 input buffer in bytes.
+ *
+ * POST-CONDITIONS
+ * <return> Zero on success.
+ *
+ * HISTORY
+ * November 12, 1997 - Andrew E. Mileski
+ * Written, tested, and released.
+ */
+int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
+{
+ unsigned c, i, max_val, utf_char;
+ int utf_cnt;
+ int u_len = 0;
+
+ memset(ocu, 0, sizeof(dstring) * length);
+ ocu[0] = 8;
+ max_val = 0xffU;
+
+try_again:
+ utf_char = 0U;
+ utf_cnt = 0U;
+ for (i = 0U; i < utf->u_len; i++) {
+ c = (unsigned)utf->u_name[i];
+
+ /* Complete a multi-byte UTF-8 character */
+ if (utf_cnt) {
+ utf_char = (utf_char << 6) | (c & 0x3fU);
+ if (--utf_cnt)
+ continue;
+ } else {
+ /* Check for a multi-byte UTF-8 character */
+ if (c & 0x80U) {
+ /* Start a multi-byte UTF-8 character */
+ if ((c & 0xe0U) == 0xc0U) {
+ utf_char = c & 0x1fU;
+ utf_cnt = 1;
+ } else if ((c & 0xf0U) == 0xe0U) {
+ utf_char = c & 0x0fU;
+ utf_cnt = 2;
+ } else if ((c & 0xf8U) == 0xf0U) {
+ utf_char = c & 0x07U;
+ utf_cnt = 3;
+ } else if ((c & 0xfcU) == 0xf8U) {
+ utf_char = c & 0x03U;
+ utf_cnt = 4;
+ } else if ((c & 0xfeU) == 0xfcU) {
+ utf_char = c & 0x01U;
+ utf_cnt = 5;
+ } else
+ goto error_out;
+ continue;
+ } else
+ /* Single byte UTF-8 character (most common) */
+ utf_char = c;
+ }
+
+ /* Choose no compression if necessary */
+ if (utf_char > max_val) {
+ if ( 0xffU == max_val ) {
+ max_val = 0xffffU;
+ ocu[0] = (Uint8)0x10U;
+ goto try_again;
+ }
+ goto error_out;
+ }
+
+ if (max_val == 0xffffU)
+ ocu[++u_len] = (Uint8)(utf_char >> 8);
+ ocu[++u_len] = (Uint8)(utf_char & 0xffU);
+ }
+
+ if (utf_cnt) {
+error_out:
+#ifdef __KERNEL__
+ printk(KERN_ERR "udf: bad UTF-8 character\n");
+#endif
+ return 0;
+ }
+
+ ocu[length - 1] = (Uint8)u_len;
+ return u_len;
+}
+
+#ifdef __KERNEL__
+int udf_get_filename(Uint8 *sname, Uint8 *dname, int flen)
+{
+ struct ustr filename, unifilename;
+ int len;
+
+ if (udf_build_ustr_exact(&unifilename, sname, flen))
+ {
+ return 0;
+ }
+
+ if (!udf_CS0toUTF8(&filename, &unifilename) )
+ {
+ udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
+ return 0;
+ }
+
+ if ((len = udf_translate_to_linux(dname, filename.u_name, filename.u_len,
+ unifilename.u_name, unifilename.u_len)))
+ {
+ return len;
+ }
+ return 0;
+}
+#endif
+
+#define ILLEGAL_CHAR_MARK '_'
+#define EXT_MARK '.'
+#define CRC_MARK '#'
+#define EXT_SIZE 5
+
+int udf_translate_to_linux(Uint8 *newName, Uint8 *udfName, int udfLen, Uint8 *fidName, int fidNameLen)
+{
+ int index, newIndex = 0, needsCRC = 0;
+ int extIndex = 0, newExtIndex = 0, hasExt = 0;
+ unsigned short valueCRC;
+ Uint8 curr;
+ const Uint8 hexChar[] = "0123456789ABCDEF";
+
+ if (udfName[0] == '.' && (udfLen == 1 ||
+ (udfLen == 2 && udfName[1] == '.')))
+ {
+ needsCRC = 1;
+ newIndex = udfLen;
+ memcpy(newName, udfName, udfLen);
+ }
+ else
+ {
+ for (index = 0; index < udfLen; index++)
+ {
+ curr = udfName[index];
+ if (curr == '/' || curr == 0)
+ {
+ needsCRC = 1;
+ curr = ILLEGAL_CHAR_MARK;
+ while (index+1 < udfLen && (udfName[index+1] == '/' ||
+ udfName[index+1] == 0))
+ index++;
+ }
+ if (curr == EXT_MARK && (udfLen - index - 1) <= EXT_SIZE)
+ {
+ if (udfLen == index + 1)
+ hasExt = 0;
+ else
+ {
+ hasExt = 1;
+ extIndex = index;
+ newExtIndex = newIndex;
+ }
+ }
+ if (newIndex < 256)
+ newName[newIndex++] = curr;
+ else
+ needsCRC = 1;
+ }
+ }
+ if (needsCRC)
+ {
+ Uint8 ext[EXT_SIZE];
+ int localExtIndex = 0;
+
+ if (hasExt)
+ {
+ int maxFilenameLen;
+ for(index = 0; index<EXT_SIZE && extIndex + index +1 < udfLen;
+ index++ )
+ {
+ curr = udfName[extIndex + index + 1];
+
+ if (curr == '/' || curr == 0)
+ {
+ needsCRC = 1;
+ curr = ILLEGAL_CHAR_MARK;
+ while(extIndex + index + 2 < udfLen && (index + 1 < EXT_SIZE
+ && (udfName[extIndex + index + 2] == '/' ||
+ udfName[extIndex + index + 2] == 0)))
+ index++;
+ }
+ ext[localExtIndex++] = curr;
+ }
+ maxFilenameLen = 250 - localExtIndex;
+ if (newIndex > maxFilenameLen)
+ newIndex = maxFilenameLen;
+ else
+ newIndex = newExtIndex;
+ }
+ else if (newIndex > 250)
+ newIndex = 250;
+ newName[newIndex++] = CRC_MARK;
+ valueCRC = udf_crc(fidName, fidNameLen, 0);
+ newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12];
+ newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8];
+ newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4];
+ newName[newIndex++] = hexChar[(valueCRC & 0x000f)];
+
+ if (hasExt)
+ {
+ newName[newIndex++] = EXT_MARK;
+ for (index = 0;index < localExtIndex ;index++ )
+ newName[newIndex++] = ext[index];
+ }
+ }
+ return newIndex;
+}
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index b6a1f8ef6..27d404ca1 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -935,7 +935,7 @@ static struct file_system_type ufs_fs_type = {
NULL
};
-__initfunc(int init_ufs_fs(void))
+int __init init_ufs_fs(void)
{
return register_filesystem(&ufs_fs_type);
}
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c
index b7214fc49..99069517e 100644
--- a/fs/ufs/truncate.c
+++ b/fs/ufs/truncate.c
@@ -455,7 +455,8 @@ void ufs_truncate (struct inode * inode)
break;
if (IS_SYNC(inode) && (inode->i_state & I_DIRTY))
ufs_sync_inode (inode);
- current->counter = 0;
+ run_task_queue(&tq_disk);
+ current->policy |= SCHED_YIELD;
schedule ();
diff --git a/fs/umsdos/Makefile b/fs/umsdos/Makefile
index f4c8dfb53..8856feba7 100644
--- a/fs/umsdos/Makefile
+++ b/fs/umsdos/Makefile
@@ -8,7 +8,7 @@
# Note 2: the CFLAGS definitions are now in the main makefile.
O_TARGET := umsdos.o
-O_OBJS := dir.o file.o inode.o ioctl.o mangle.o namei.o \
+O_OBJS := dir.o inode.o ioctl.o mangle.o namei.o \
rdir.o symlink.o emd.o check.o
M_OBJS := $(O_TARGET)
diff --git a/fs/umsdos/check.c b/fs/umsdos/check.c
index e9860caae..1eda3df93 100644
--- a/fs/umsdos/check.c
+++ b/fs/umsdos/check.c
@@ -92,24 +92,7 @@ void check_inode (struct inode *inode)
}
printk (" (i_patched=%d)", inode->u.umsdos_i.i_patched);
-
- if (inode->i_op == NULL) {
- printk (" (i_op is NULL)\n");
- } else if (inode->i_op == &umsdos_dir_inode_operations) {
- printk (" (i_op is umsdos_dir_inode_operations)\n");
- } else if (inode->i_op == &umsdos_file_inode_operations) {
- printk (" (i_op is umsdos_file_inode_operations)\n");
- } else if (inode->i_op == &umsdos_file_inode_operations_no_bmap) {
- printk (" (i_op is umsdos_file_inode_operations_no_bmap)\n");
- } else if (inode->i_op == &umsdos_file_inode_operations_readpage) {
- printk (" (i_op is umsdos_file_inode_operations_readpage)\n");
- } else if (inode->i_op == &umsdos_rdir_inode_operations) {
- printk (" (i_op is umsdos_rdir_inode_operations)\n");
- } else if (inode->i_op == &umsdos_symlink_inode_operations) {
- printk (" (i_op is umsdos_symlink_inode_operations)\n");
- } else {
- printk (" (i_op is UNKNOWN: %p)\n", inode->i_op);
- }
+
} else {
printk (KERN_DEBUG "* inode is NULL\n");
}
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index 34fe302d7..c09c293cf 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -393,7 +393,6 @@ void umsdos_lookup_patch_new(struct dentry *dentry, struct umsdos_info *info)
inode->i_uid = entry->uid;
inode->i_gid = entry->gid;
- MSDOS_I (inode)->i_binary = 1;
/* #Specification: umsdos / i_nlink
* The nlink field of an inode is maintained by the MSDOS file system
* for directory and by UMSDOS for other files. The logic is that
@@ -832,8 +831,8 @@ struct inode_operations umsdos_dir_inode_operations =
UMSDOS_rename, /* rename */
NULL, /* readlink */
NULL, /* followlink */
- fat_bmap, /* get_block */
- block_read_full_page, /* readpage */
+ NULL, /* get_block */
+ NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
NULL, /* truncate */
diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c
index d5a7a9578..d9b00e8c9 100644
--- a/fs/umsdos/emd.c
+++ b/fs/umsdos/emd.c
@@ -34,7 +34,6 @@ ssize_t umsdos_file_read_kmem ( struct file *filp,
mm_segment_t old_fs = get_fs ();
set_fs (KERNEL_DS);
- MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2;
ret = fat_file_read (filp, buf, count, &filp->f_pos);
set_fs (old_fs);
return ret;
@@ -54,15 +53,6 @@ ssize_t umsdos_file_write_kmem_real (struct file * filp,
mm_segment_t old_fs = get_fs ();
ssize_t ret;
- /* 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 the unlikely event that they are > 512 bytes and
- * can be compressed.
- * FIXME: should we set it when reading symlinks too?
- */
-
- MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2;
-
set_fs (KERNEL_DS);
ret = fat_file_write (filp, buf, count, &filp->f_pos);
set_fs (old_fs);
diff --git a/fs/umsdos/file.c b/fs/umsdos/file.c
deleted file mode 100644
index b930c46ae..000000000
--- a/fs/umsdos/file.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * linux/fs/umsdos/file.c
- *
- * Written 1993 by Jacques Gelinas
- * inspired from linux/fs/msdos/file.c Werner Almesberger
- *
- * Extended MS-DOS regular file handling primitives
- */
-
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/msdos_fs.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/umsdos_fs.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-/*
- * Read a file into user space memory
- */
-static ssize_t UMSDOS_file_read (
- struct file *filp,
- char *buf,
- size_t count,
- loff_t * ppos
-)
-{
- struct dentry *dentry = filp->f_dentry;
- struct inode *inode = dentry->d_inode;
-
- int ret = fat_file_read (filp, buf, count, ppos);
-
- /* We have to set the access time because msdos don't care */
- if (!IS_RDONLY (inode)) {
- inode->i_atime = CURRENT_TIME;
- mark_inode_dirty(inode);
- }
- return ret;
-}
-
-
-/*
- * Write a file from user space memory
- */
-static ssize_t UMSDOS_file_write (
- struct file *filp,
- const char *buf,
- size_t count,
- loff_t * ppos)
-{
- return fat_file_write (filp, buf, count, ppos);
-}
-
-
-/*
- * Truncate a file to 0 length.
- */
-static void UMSDOS_truncate (struct inode *inode)
-{
- Printk (("UMSDOS_truncate\n"));
- if (!IS_RDONLY (inode)) {
- fat_truncate (inode);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- mark_inode_dirty(inode);
- }
-}
-
-/* Function for normal file system (512 bytes hardware sector size) */
-struct file_operations umsdos_file_operations =
-{
- 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, /* flush */
- NULL, /* release */
- file_fsync /* fsync */
-};
-
-struct inode_operations umsdos_file_inode_operations =
-{
- &umsdos_file_operations, /* 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_bmap, /* get_block */
- block_read_full_page, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- UMSDOS_truncate, /* truncate */
- NULL, /* permission */
- fat_smap, /* smap */
- NULL /* revalidate */
-};
-
-/* For other with larger and unaligned file system */
-struct file_operations umsdos_file_operations_no_bmap =
-{
- NULL, /* lseek - default */
- UMSDOS_file_read, /* read */
- UMSDOS_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- fat_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- NULL, /* release */
- file_fsync /* fsync */
-};
-
-struct inode_operations umsdos_file_inode_operations_no_bmap =
-{
- &umsdos_file_operations_no_bmap, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- UMSDOS_truncate, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-/* 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, /* flush */
- 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 */
- NULL, /* get_block */
- fat_readpage, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- UMSDOS_truncate, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c
index 81806ca18..171aa15dc 100644
--- a/fs/umsdos/inode.c
+++ b/fs/umsdos/inode.c
@@ -42,7 +42,7 @@ void fill_new_filp (struct file *filp, struct dentry *dentry)
filp->f_reada = 1;
filp->f_flags = O_RDWR;
filp->f_dentry = dentry;
- filp->f_op = &umsdos_file_operations;
+ filp->f_op = dentry->d_inode->i_op->default_file_ops;
}
@@ -146,19 +146,7 @@ dentry, f_pos));
umsdos_set_dirinfo_new(dentry, f_pos);
if (S_ISREG (inode->i_mode)) {
- if (MSDOS_SB (inode->i_sb)->cvf_format) {
- if (MSDOS_SB (inode->i_sb)->cvf_format->flags & CVF_USE_READPAGE) {
- inode->i_op = &umsdos_file_inode_operations_readpage;
- } else {
- inode->i_op = &umsdos_file_inode_operations_no_bmap;
- }
- } else {
- if (inode->i_op->bmap != NULL) {
- inode->i_op = &umsdos_file_inode_operations;
- } else {
- inode->i_op = &umsdos_file_inode_operations_no_bmap;
- }
- }
+ /* All set */
} else if (S_ISDIR (inode->i_mode)) {
umsdos_setup_dir(dentry);
} else if (S_ISLNK (inode->i_mode)) {
@@ -446,7 +434,7 @@ static struct file_system_type umsdos_fs_type =
NULL
};
-__initfunc (int init_umsdos_fs (void))
+int __init init_umsdos_fs (void)
{
return register_filesystem (&umsdos_fs_type);
}
diff --git a/fs/umsdos/symlink.c b/fs/umsdos/symlink.c
index 2d08a35d8..8f94230e3 100644
--- a/fs/umsdos/symlink.c
+++ b/fs/umsdos/symlink.c
@@ -135,7 +135,7 @@ struct inode_operations umsdos_symlink_inode_operations =
NULL, /* rename */
UMSDOS_readlink, /* readlink */
UMSDOS_followlink, /* followlink */
- fat_bmap, /* get_block */
+ fat_get_block, /* get_block */
block_read_full_page, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index ad241c3cd..0f23487ba 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -982,35 +982,6 @@ int vfat_create(struct inode *dir,struct dentry* dentry,int mode)
return 0;
}
-static int vfat_create_dotdirs(struct inode *dir, struct inode *parent)
-{
- struct super_block *sb = dir->i_sb;
- struct buffer_head *bh;
- struct msdos_dir_entry *de;
- __u16 date, time;
-
- if ((bh = fat_add_cluster1(dir)) == NULL) return -ENOSPC;
- /* zeroed out, so... */
- fat_date_unix2dos(dir->i_mtime,&time,&date);
- de = (struct msdos_dir_entry*)&bh->b_data[0];
- memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);
- memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);
- de[0].attr = de[1].attr = ATTR_DIR;
- de[0].ctime = de[0].time = de[1].ctime = de[1].time = CT_LE_W(time);
- de[0].adate = de[0].cdate = de[0].date = de[1].adate =
- de[1].cdate = de[1].date = CT_LE_W(date);
- de[0].start = CT_LE_W(MSDOS_I(dir)->i_logstart);
- de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16);
- de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart);
- de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16);
- fat_mark_buffer_dirty(sb, bh, 1);
- fat_brelse(sb, bh);
- dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- mark_inode_dirty(dir);
-
- return 0;
-}
-
static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
struct buffer_head *bh, struct msdos_dir_entry *de)
{
@@ -1110,8 +1081,7 @@ int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode)
dir->i_version = event;
dir->i_nlink++;
inode->i_nlink = 2; /* no need to mark them dirty */
-
- res = vfat_create_dotdirs(inode, dir);
+ res = fat_new_dir(inode, dir, 1);
if (res < 0)
goto mkdir_failed;
dentry->d_time = dentry->d_parent->d_inode->i_version;