summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.in83
-rw-r--r--fs/Makefile11
-rw-r--r--fs/autofs/init.c15
-rw-r--r--fs/autofs4/.cvsignore2
-rw-r--r--fs/autofs4/Makefile35
-rw-r--r--fs/autofs4/autofs_i.h175
-rw-r--r--fs/autofs4/expire.c234
-rw-r--r--fs/autofs4/init.c35
-rw-r--r--fs/autofs4/inode.c423
-rw-r--r--fs/autofs4/inohash.c68
-rw-r--r--fs/autofs4/root.c624
-rw-r--r--fs/autofs4/symlink.c34
-rw-r--r--fs/autofs4/waitq.c251
-rw-r--r--fs/block_dev.c2
-rw-r--r--fs/dcache.c26
-rw-r--r--fs/devices.c4
-rw-r--r--fs/dquot.c41
-rw-r--r--fs/ext2/namei.c20
-rw-r--r--fs/fat/misc.c1
-rw-r--r--fs/filesystems.c4
-rw-r--r--fs/hpfs/hpfs_fn.h4
-rw-r--r--fs/inode.c23
-rw-r--r--fs/isofs/util.c5
-rw-r--r--fs/namei.c6
-rw-r--r--fs/ncpfs/dir.c24
-rw-r--r--fs/ncpfs/file.c27
-rw-r--r--fs/ncpfs/inode.c2
-rw-r--r--fs/ncpfs/ioctl.c1
-rw-r--r--fs/ncpfs/mmap.c12
-rw-r--r--fs/nfs/write.c4
-rw-r--r--fs/nfsd/nfsfh.c2
-rw-r--r--fs/open.c9
-rw-r--r--fs/partitions/Config.in27
-rw-r--r--fs/partitions/check.c1
-rw-r--r--fs/partitions/sgi.c8
-rw-r--r--fs/partitions/sun.c6
-rw-r--r--fs/partitions/ultrix.c27
-rw-r--r--fs/partitions/ultrix.h10
-rw-r--r--fs/select.c130
-rw-r--r--fs/super.c127
-rw-r--r--fs/udf/dir.c14
-rw-r--r--fs/udf/directory.c4
-rw-r--r--fs/udf/file.c317
-rw-r--r--fs/udf/fsync.c29
-rw-r--r--fs/udf/ialloc.c11
-rw-r--r--fs/udf/inode.c467
-rw-r--r--fs/udf/lowlevel.c26
-rw-r--r--fs/udf/misc.c19
-rw-r--r--fs/udf/namei.c62
-rw-r--r--fs/udf/partition.c275
-rw-r--r--fs/udf/super.c91
-rw-r--r--fs/udf/symlink.c62
-rw-r--r--fs/udf/truncate.c51
-rw-r--r--fs/udf/udf_i.h7
-rw-r--r--fs/udf/udf_sb.h4
-rw-r--r--fs/udf/udfdecl.h22
-rw-r--r--fs/udf/udftime.c2
-rw-r--r--fs/udf/unicode.c98
58 files changed, 3064 insertions, 1040 deletions
diff --git a/fs/Config.in b/fs/Config.in
index daad6d182..085e191cb 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -6,30 +6,27 @@ comment 'Filesystems'
bool 'Quota support' CONFIG_QUOTA
tristate 'Kernel automounter support' CONFIG_AUTOFS_FS
+tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'ADFS filesystem support (read only) (EXPERIMENTAL)' CONFIG_ADFS_FS
-fi
+dep_tristate 'ADFS filesystem support (read only) (EXPERIMENTAL)' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
+
tristate 'Amiga FFS filesystem support' CONFIG_AFFS_FS
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'Apple Macintosh filesystem support (EXPERIMENTAL)' CONFIG_HFS_FS
- tristate 'BFS filesystem (read only) support (EXPERIMENTAL)' CONFIG_BFS_FS
- if [ "$CONFIG_BFS_FS" != "n" ]; then
- bool ' BFS filesystem write support (DANGEROUS)' CONFIG_BFS_FS_WRITE
- fi
-fi
+
+dep_tristate 'Apple Macintosh filesystem support (EXPERIMENTAL)' CONFIG_HFS_FS $CONFIG_EXPERIMENTAL
+
+dep_tristate 'BFS filesystem (read only) support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL
+dep_bool ' BFS filesystem write support (DANGEROUS)' CONFIG_BFS_FS_WRITE $CONFIG_BFS_FS
+
# msdos filesystems
tristate 'DOS FAT fs support' CONFIG_FAT_FS
dep_tristate ' MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
dep_tristate ' UMSDOS: Unix-like filesystem on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
dep_tristate ' VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
-
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'EFS filesystem support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS
-fi
+dep_tristate 'EFS filesystem support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL
tristate 'Compressed ROM filessytem support' CONFIG_CRAMFS
+
tristate 'ISO 9660 CDROM filesystem support' CONFIG_ISO9660_FS
if [ "$CONFIG_ISO9660_FS" != "n" ]; then
bool ' Microsoft Joliet CDROM extensions' CONFIG_JOLIET
@@ -39,39 +36,35 @@ else
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
- bool ' NTFS write support (DANGEROUS)' CONFIG_NTFS_RW
-fi
+dep_bool ' NTFS write support (DANGEROUS)' CONFIG_NTFS_RW $CONFIG_NTFS_FS $CONFIG_EXPERIMENTAL
+
tristate 'OS/2 HPFS filesystem support' CONFIG_HPFS_FS
+
bool '/proc filesystem support' CONFIG_PROC_FS
-if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
- # It compiles as a module for testing only. It should not be used
- # as a module in general. If we make this "tristate", a bunch of people
- # who don't know what they are doing turn it on and complain when it
- # breaks.
- bool '/dev/pts filesystem for Unix98 PTYs' CONFIG_DEVPTS_FS
-fi
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate 'QNX4 filesystem support (read only) (EXPERIMENTAL)' CONFIG_QNX4FS_FS
- if [ "$CONFIG_QNX4FS_FS" != "n" ]; then
- bool ' QNX4FS write support (DANGEROUS)' CONFIG_QNX4FS_RW
- fi
-fi
+
+# It compiles as a module for testing only. It should not be used
+# as a module in general. If we make this "tristate", a bunch of people
+# who don't know what they are doing turn it on and complain when it
+# breaks.
+dep_bool '/dev/pts filesystem for Unix98 PTYs' CONFIG_DEVPTS_FS $CONFIG_UNIX98_PTYS
+
+dep_tristate 'QNX4 filesystem support (read only) (EXPERIMENTAL)' CONFIG_QNX4FS_FS $CONFIG_EXPERIMENTAL
+dep_bool ' QNX4FS write support (DANGEROUS)' CONFIG_QNX4FS_RW $CONFIG_QNX4FS_FS
+
tristate 'ROM filesystem support' CONFIG_ROMFS_FS
+
tristate 'Second extended fs support' CONFIG_EXT2_FS
+
tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
-if [ "$CONFIG_SYSV_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' SYSV filesystem write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE
-fi
+dep_bool ' SYSV filesystem write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE $CONFIG_SYSV_FS $CONFIG_EXPERIMENTAL
+
tristate 'UDF filesystem support (read only)' CONFIG_UDF_FS
-if [ "$CONFIG_UDF_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' UDF write support (DANGEROUS)' CONFIG_UDF_RW
-fi
+dep_bool ' UDF write support (DANGEROUS)' CONFIG_UDF_RW $CONFIG_UDF_FS $CONFIG_EXPERIMENTAL
+
tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS
-if [ "$CONFIG_UFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' UFS filesystem write support (DANGEROUS)' CONFIG_UFS_FS_WRITE
-fi
+dep_bool ' UFS filesystem write support (DANGEROUS)' CONFIG_UFS_FS_WRITE $CONFIG_UFS_FS $CONFIG_EXPERIMENTAL
if [ "$CONFIG_NET" = "y" ]; then
@@ -81,16 +74,12 @@ comment 'Network File Systems'
if [ "$CONFIG_INET" = "y" ]; then
tristate 'Coda filesystem support (advanced network fs)' CONFIG_CODA_FS
+
tristate 'NFS filesystem support' CONFIG_NFS_FS
- if [ "$CONFIG_NFS_FS" = "y" -a "$CONFIG_IP_PNP" = "y" ]; then
- bool ' Root file system on NFS' CONFIG_ROOT_NFS
- fi
+ dep_bool ' Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP
+
tristate 'NFS server support' CONFIG_NFSD
- if [ "$CONFIG_NFSD" != "n" ]; then
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' Provide NFSv3 server support (EXPERIMENTAL)' CONFIG_NFSD_V3
- fi
- fi
+ dep_bool ' Provide NFSv3 server support (EXPERIMENTAL)' CONFIG_NFSD_V3 $CONFIG_NFSD $CONFIG_EXPERIMENTAL
if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
define_tristate CONFIG_SUNRPC y
diff --git a/fs/Makefile b/fs/Makefile
index eadd9e16c..e79d69c1b 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -18,7 +18,8 @@ O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \
MOD_LIST_NAME := FS_MODULES
ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
hpfs sysv smbfs ncpfs ufs efs affs romfs autofs hfs lockd \
- nfsd nls devpts adfs partitions qnx4 udf bfs cramfs openpromfs
+ nfsd nls devpts adfs partitions qnx4 udf bfs cramfs openpromfs \
+ autofs4
SUB_DIRS := partitions
@@ -253,6 +254,14 @@ else
endif
endif
+ifeq ($(CONFIG_AUTOFS4_FS),y)
+SUB_DIRS += autofs4
+else
+ ifeq ($(CONFIG_AUTOFS4_FS),m)
+ MOD_SUB_DIRS += autofs4
+ endif
+endif
+
ifeq ($(CONFIG_ADFS_FS),y)
SUB_DIRS += adfs
else
diff --git a/fs/autofs/init.c b/fs/autofs/init.c
index a4c5184f2..5c31dc889 100644
--- a/fs/autofs/init.c
+++ b/fs/autofs/init.c
@@ -21,25 +21,18 @@ static struct file_system_type autofs_fs_type = {
NULL
};
-#ifdef MODULE
-int init_module(void)
+static int __init init_autofs_fs(void)
{
return register_filesystem(&autofs_fs_type);
}
-void cleanup_module(void)
+static void __exit exit_autofs_fs(void)
{
unregister_filesystem(&autofs_fs_type);
}
-#else /* MODULE */
-
-int __init init_autofs_fs(void)
-{
- return register_filesystem(&autofs_fs_type);
-}
-
-#endif /* !MODULE */
+module_init(init_autofs_fs)
+module_exit(exit_autofs_fs)
#ifdef DEBUG
void autofs_say(const char *name, int len)
diff --git a/fs/autofs4/.cvsignore b/fs/autofs4/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/fs/autofs4/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/fs/autofs4/Makefile b/fs/autofs4/Makefile
new file mode 100644
index 000000000..0095b8aed
--- /dev/null
+++ b/fs/autofs4/Makefile
@@ -0,0 +1,35 @@
+#
+# Makefile for the linux autofs-filesystem routines.
+#
+# We can build this either out of the kernel tree or the autofs tools tree.
+#
+
+O_TARGET := autofs4.o
+O_OBJS := inohash.o init.o inode.o root.o symlink.o waitq.o expire.o
+
+M_OBJS := $(O_TARGET)
+
+ifdef TOPDIR
+#
+# Part of the kernel code
+#
+include $(TOPDIR)/Rules.make
+else
+#
+# Standalone (handy for development)
+#
+include ../Makefile.rules
+
+CFLAGS += -D__KERNEL__ -DMODULE $(KFLAGS) -I../include -I$(KINCLUDE) $(MODFLAGS)
+
+all: $(O_TARGET)
+
+$(O_TARGET): $(O_OBJS)
+ $(LD) -r -o $(O_TARGET) $(O_OBJS)
+
+install: $(O_TARGET)
+ install -c $(O_TARGET) /lib/modules/`uname -r`/fs
+
+clean:
+ rm -f *.o *.s
+endif
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
new file mode 100644
index 000000000..e8487efd6
--- /dev/null
+++ b/fs/autofs4/autofs_i.h
@@ -0,0 +1,175 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * linux/fs/autofs/autofs_i.h
+ *
+ * Copyright 1997-1998 Transmeta Corporation - All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/* Internal header file for autofs */
+
+#include <linux/auto_fs.h>
+#include <linux/list.h>
+
+/* This is the range of ioctl() numbers we claim as ours */
+#define AUTOFS_IOC_FIRST AUTOFS_IOC_READY
+#define AUTOFS_IOC_COUNT 32
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+
+/* #define DEBUG */
+
+#ifdef DEBUG
+#define DPRINTK(D) do{ printk("pid %d: ", current->pid); printk D; } while(0)
+#else
+#define DPRINTK(D) do {} while(0)
+#endif
+
+#define AUTOFS_SUPER_MAGIC 0x0187
+
+/*
+ * If the daemon returns a negative response (AUTOFS_IOC_FAIL) then the
+ * kernel will keep the negative response cached for up to the time given
+ * here, although the time can be shorter if the kernel throws the dcache
+ * entry away. This probably should be settable from user space.
+ */
+#define AUTOFS_NEGATIVE_TIMEOUT (60*HZ) /* 1 minute */
+
+/* Unified info structure. This is pointed to by both the dentry and
+ inode structures. Each file in the filesystem has an instance of this
+ structure. It holds a reference to the dentry, so dentries are never
+ flushed while the file exists. All name lookups are dealt with at the
+ dentry level, although the filesystem can interfere in the validation
+ process. Readdir is implemented by traversing the dentry lists. */
+struct autofs_info {
+ struct dentry *dentry;
+ struct inode *inode;
+
+ int flags;
+
+ struct autofs_sb_info *sbi;
+ struct list_head ino_hash;
+ unsigned long last_used;
+
+ ino_t ino;
+ mode_t mode;
+ size_t size;
+
+ void (*free)(struct autofs_info *);
+ union {
+ const char *symlink;
+ } u;
+};
+
+#define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */
+
+struct autofs_inohash {
+ struct list_head head;
+};
+
+struct autofs_wait_queue {
+ wait_queue_head_t queue;
+ struct autofs_wait_queue *next;
+ autofs_wqt_t wait_queue_token;
+ /* We use the following to see what we are waiting for */
+ int hash;
+ int len;
+ char *name;
+ /* This is for status reporting upon return */
+ int status;
+ int wait_ctr;
+};
+
+#define AUTOFS_ROOT_INO 1
+#define AUTOFS_FIRST_INO 2
+
+#define AUTOFS_SBI_MAGIC 0x6d4a556d
+
+struct autofs_sb_info {
+ u32 magic;
+ struct file *pipe;
+ pid_t oz_pgrp;
+ int catatonic;
+ int version;
+ unsigned long exp_timeout;
+ ino_t next_ino;
+ struct super_block *sb;
+ struct autofs_wait_queue *queues; /* Wait queue pointer */
+ struct autofs_inohash ihash;
+};
+
+static inline struct autofs_sb_info *autofs4_sbi(struct super_block *sb)
+{
+ return (struct autofs_sb_info *)(sb->u.generic_sbp);
+}
+
+static inline struct autofs_info *autofs4_dentry_ino(struct dentry *dentry)
+{
+ return (struct autofs_info *)(dentry->d_fsdata);
+}
+
+/* autofs4_oz_mode(): do we see the man behind the curtain? (The
+ processes which do manipulations for us in user space sees the raw
+ filesystem without "magic".) */
+
+static inline int autofs4_oz_mode(struct autofs_sb_info *sbi) {
+ return sbi->catatonic || current->pgrp == sbi->oz_pgrp;
+}
+
+/* Does a dentry have some pending activity? */
+static inline int autofs4_ispending(struct dentry *dentry)
+{
+ struct autofs_info *inf = autofs4_dentry_ino(dentry);
+
+ return (dentry->d_flags & DCACHE_AUTOFS_PENDING) ||
+ (inf != NULL && inf->flags & AUTOFS_INF_EXPIRING);
+}
+
+/* Inode hash operations */
+void autofs4_init_ihash(struct autofs_inohash *);
+void autofs4_ihash_insert(struct autofs_inohash *ih, struct autofs_info *ino);
+void autofs4_ihash_delete(struct autofs_info *ino);
+void autofs4_ihash_nuke(struct autofs_inohash *ih);
+struct autofs_info *autofs4_ihash_find(struct autofs_inohash *ih, ino_t ino);
+
+struct autofs_info *autofs4_init_inf(struct autofs_sb_info *, mode_t mode);
+void autofs4_free_ino(struct autofs_info *);
+
+/* Expiration */
+int is_autofs4_dentry(struct dentry *);
+int autofs4_expire_run(struct super_block *, struct autofs_sb_info *,
+ struct autofs_packet_expire *);
+int autofs4_expire_multi(struct super_block *, struct autofs_sb_info *, int *);
+
+/* Operations structures */
+
+extern struct inode_operations autofs4_symlink_inode_operations;
+extern struct inode_operations autofs4_dir_inode_operations;
+extern struct inode_operations autofs4_root_inode_operations;
+
+/* Initializing function */
+
+struct super_block *autofs4_read_super(struct super_block *, void *,int);
+struct autofs_info *autofs4_init_ino(struct autofs_info *, struct autofs_sb_info *sbi, mode_t mode);
+
+/* Queue management functions */
+
+enum autofs_notify
+{
+ NFY_NONE,
+ NFY_MOUNT,
+ NFY_EXPIRE
+};
+
+int autofs4_wait(struct autofs_sb_info *,struct qstr *, enum autofs_notify);
+int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int);
+void autofs4_catatonic_mode(struct autofs_sb_info *);
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
new file mode 100644
index 000000000..2318b9aec
--- /dev/null
+++ b/fs/autofs4/expire.c
@@ -0,0 +1,234 @@
+/* -*- linux-c -*- --------------------------------------------------------- *
+ *
+ * linux/fs/autofs/expire.c
+ *
+ * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
+ * Copyright 1999 Jeremy Fitzhardinge <jeremy@goop.org>
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+
+#include "autofs_i.h"
+
+/*
+ * Determine if a dentry tree is in use. This is much the
+ * same as the standard is_root_busy() function, except
+ * that :-
+ * - the extra dentry reference in autofs dentries is not
+ * considered to be busy
+ * - mountpoints within the tree are not busy
+ * - it traverses across mountpoints
+ * XXX doesn't consider children of covered dentries at mountpoints
+ */
+static int is_tree_busy(struct dentry *root)
+{
+ struct dentry *this_parent;
+ struct list_head *next;
+ int count;
+
+ root = root->d_mounts;
+
+ count = root->d_count;
+ this_parent = root;
+
+ DPRINTK(("is_tree_busy: starting at %.*s/%.*s, d_count=%d\n",
+ root->d_covers->d_parent->d_name.len,
+ root->d_covers->d_parent->d_name.name,
+ root->d_name.len, root->d_name.name,
+ root->d_count));
+
+ /* Ignore autofs's extra reference */
+ if (is_autofs4_dentry(root)) {
+ DPRINTK(("is_tree_busy: autofs\n"));
+ count--;
+ }
+
+ /* Mountpoints don't count */
+ if (root->d_mounts != root ||
+ root->d_covers != root) {
+ DPRINTK(("is_tree_busy: mountpoint\n"));
+ count--;
+ }
+
+repeat:
+ next = this_parent->d_mounts->d_subdirs.next;
+resume:
+ while (next != &this_parent->d_mounts->d_subdirs) {
+ int adj = 0;
+ struct list_head *tmp = next;
+ struct dentry *dentry = list_entry(tmp, struct dentry,
+ d_child);
+
+ next = tmp->next;
+
+ dentry = dentry->d_mounts;
+
+ DPRINTK(("is_tree_busy: considering %.*s/%.*s, d_count=%d, count=%d\n",
+ this_parent->d_name.len,
+ this_parent->d_name.name,
+ dentry->d_covers->d_name.len,
+ dentry->d_covers->d_name.name,
+ dentry->d_count, count));
+
+ /* Decrement count for unused children */
+ count += (dentry->d_count - 1);
+
+ /* Mountpoints don't count */
+ if (dentry->d_mounts != dentry ||
+ dentry->d_covers != dentry) {
+ DPRINTK(("is_tree_busy: mountpoint\n"));
+ adj++;
+ }
+
+ /* Ignore autofs's extra reference */
+ if (is_autofs4_dentry(dentry)) {
+ DPRINTK(("is_tree_busy: autofs\n"));
+ adj++;
+ }
+
+ count -= adj;
+
+ if (!list_empty(&dentry->d_mounts->d_subdirs)) {
+ this_parent = dentry->d_mounts;
+ goto repeat;
+ }
+
+ /* root is busy if any leaf is busy */
+ if (dentry->d_count != adj) {
+ DPRINTK(("is_tree_busy: busy leaf (d_count=%d adj=%d)\n",
+ dentry->d_count, adj));
+ return 1;
+ }
+ }
+ /*
+ * All done at this level ... ascend and resume the search.
+ */
+ if (this_parent != root) {
+ next = this_parent->d_covers->d_child.next;
+ this_parent = this_parent->d_covers->d_parent;
+ goto resume;
+ }
+
+ DPRINTK(("is_tree_busy: count=%d\n", count));
+ return count != 0; /* remaining users? */
+}
+
+/*
+ * Find an eligible tree to time-out
+ * A tree is eligible if :-
+ * - it is unused by any user process
+ * - it has been unused for exp_timeout time
+ */
+static struct dentry *autofs4_expire(struct super_block *sb,
+ struct autofs_sb_info *sbi,
+ int do_now)
+{
+ unsigned long now = jiffies; /* snapshot of now */
+ unsigned long timeout;
+ struct dentry *root = sb->s_root;
+ struct list_head *tmp;
+
+ if (!sbi->exp_timeout || !root)
+ return NULL;
+
+ timeout = sbi->exp_timeout;
+
+ for(tmp = root->d_subdirs.next;
+ tmp != &root->d_subdirs;
+ tmp = tmp->next) {
+ struct autofs_info *ino;
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+
+ if (dentry->d_inode == NULL)
+ continue;
+
+ ino = autofs4_dentry_ino(dentry);
+
+ if (ino == NULL) {
+ /* dentry in the process of being deleted */
+ continue;
+ }
+
+ /* No point expiring a pending mount */
+ if (dentry->d_flags & DCACHE_AUTOFS_PENDING)
+ continue;
+
+ if (!do_now) {
+ /* Too young to die */
+ if (time_after(ino->last_used+timeout, now))
+ continue;
+
+ /* update last_used here :-
+ - obviously makes sense if it is in use now
+ - less obviously, prevents rapid-fire expire
+ attempts if expire fails the first time */
+ ino->last_used = now;
+ }
+
+ if (!is_tree_busy(dentry)) {
+ DPRINTK(("autofs_expire: returning %p %.*s\n",
+ dentry, dentry->d_name.len, dentry->d_name.name));
+ /* Start from here next time */
+ list_del(&root->d_subdirs);
+ list_add(&root->d_subdirs, &dentry->d_child);
+ return dentry;
+ }
+ }
+
+ return NULL;
+}
+
+/* Perform an expiry operation */
+int autofs4_expire_run(struct super_block *sb,
+ struct autofs_sb_info *sbi,
+ struct autofs_packet_expire *pkt_p)
+{
+ struct autofs_packet_expire pkt;
+ struct dentry *dentry;
+
+ memset(&pkt,0,sizeof pkt);
+
+ pkt.hdr.proto_version = sbi->version;
+ pkt.hdr.type = autofs_ptype_expire;
+
+ if ((dentry = autofs4_expire(sb, sbi, 0)) == NULL)
+ return -EAGAIN;
+
+ pkt.len = dentry->d_name.len;
+ memcpy(pkt.name, dentry->d_name.name, pkt.len);
+ pkt.name[pkt.len] = '\0';
+
+ if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
+ return -EFAULT;
+
+ return 0;
+}
+
+/* Call repeatedly until it returns -EAGAIN, meaning there's nothing
+ more to be done */
+int autofs4_expire_multi(struct super_block *sb,
+ struct autofs_sb_info *sbi, int *arg)
+{
+ struct dentry *dentry;
+ int ret = -EAGAIN;
+ int do_now = 0;
+
+ if (arg && get_user(do_now, arg))
+ return -EFAULT;
+
+ if ((dentry = autofs4_expire(sb, sbi, do_now)) != NULL) {
+ struct autofs_info *de_info = autofs4_dentry_ino(dentry);
+
+ /* This is synchronous because it makes the daemon a
+ little easier */
+ de_info->flags |= AUTOFS_INF_EXPIRING;
+ ret = autofs4_wait(sbi, &dentry->d_name, NFY_EXPIRE);
+ de_info->flags &= ~AUTOFS_INF_EXPIRING;
+ }
+
+ return ret;
+}
+
diff --git a/fs/autofs4/init.c b/fs/autofs4/init.c
new file mode 100644
index 000000000..48bf60b5f
--- /dev/null
+++ b/fs/autofs4/init.c
@@ -0,0 +1,35 @@
+/* -*- linux-c -*- --------------------------------------------------------- *
+ *
+ * linux/fs/autofs/init.c
+ *
+ * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include "autofs_i.h"
+
+static struct file_system_type autofs_fs_type = {
+ "autofs",
+ 0,
+ autofs4_read_super,
+ NULL
+};
+
+static int __init init_autofs4_fs(void)
+{
+ return register_filesystem(&autofs_fs_type);
+}
+
+static void __exit exit_autofs4_fs(void)
+{
+ unregister_filesystem(&autofs_fs_type);
+}
+
+module_init(init_autofs4_fs)
+module_exit(exit_autofs4_fs)
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
new file mode 100644
index 000000000..3d3485c9d
--- /dev/null
+++ b/fs/autofs4/inode.c
@@ -0,0 +1,423 @@
+/* -*- linux-c -*- --------------------------------------------------------- *
+ *
+ * linux/fs/autofs/inode.c
+ *
+ * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/file.h>
+#include <linux/locks.h>
+#include <asm/bitops.h>
+#include "autofs_i.h"
+#define __NO_VERSION__
+#include <linux/module.h>
+
+static void ino_lnkfree(struct autofs_info *ino)
+{
+ if (ino->u.symlink) {
+ kfree(ino->u.symlink);
+ ino->u.symlink = NULL;
+ }
+}
+
+struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
+ struct autofs_sb_info *sbi, mode_t mode)
+{
+ int reinit = 1;
+
+ if (ino == NULL) {
+ reinit = 0;
+ ino = kmalloc(sizeof(*ino), GFP_KERNEL);
+ }
+
+ if (ino == NULL)
+ return NULL;
+
+ ino->flags = 0;
+ ino->ino = sbi->next_ino++;
+ ino->mode = mode;
+ ino->inode = NULL;
+ ino->dentry = NULL;
+ ino->size = 0;
+
+ ino->last_used = jiffies;
+
+ ino->sbi = sbi;
+ INIT_LIST_HEAD(&ino->ino_hash);
+
+ if (reinit && ino->free)
+ (ino->free)(ino);
+
+ memset(&ino->u, 0, sizeof(ino->u));
+
+ ino->free = NULL;
+
+ if (S_ISLNK(mode))
+ ino->free = ino_lnkfree;
+
+ return ino;
+}
+
+void autofs4_free_ino(struct autofs_info *ino)
+{
+ autofs4_ihash_delete(ino);
+ if (ino->dentry) {
+ ino->dentry->d_fsdata = NULL;
+ if (ino->dentry->d_inode)
+ dput(ino->dentry);
+ ino->dentry = NULL;
+ }
+ if (ino->free)
+ (ino->free)(ino);
+ kfree(ino);
+}
+
+/*
+ * Dummy functions - do we ever actually want to do
+ * something here?
+ */
+static void autofs4_put_inode(struct inode *inode)
+{
+}
+
+static void autofs4_clear_inode(struct inode *inode)
+{
+}
+
+static void autofs4_put_super(struct super_block *sb)
+{
+ struct autofs_sb_info *sbi = autofs4_sbi(sb);
+
+ sb->u.generic_sbp = NULL;
+
+ if ( !sbi->catatonic )
+ autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */
+
+ kfree(sbi);
+
+ DPRINTK(("autofs: shutting down\n"));
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+}
+
+static void autofs4_umount_begin(struct super_block *sb)
+{
+ struct autofs_sb_info *sbi = autofs4_sbi(sb);
+
+ if (!sbi->catatonic)
+ autofs4_catatonic_mode(sbi);
+}
+
+static int autofs4_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static void autofs4_read_inode(struct inode *inode);
+static void autofs4_write_inode(struct inode *inode);
+
+static struct super_operations autofs4_sops = {
+ read_inode: autofs4_read_inode,
+ write_inode: autofs4_write_inode,
+ put_inode: autofs4_put_inode,
+ clear_inode: autofs4_clear_inode,
+ put_super: autofs4_put_super,
+ statfs: autofs4_statfs,
+ umount_begin: autofs4_umount_begin,
+};
+
+static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
+ pid_t *pgrp, int *minproto, int *maxproto)
+{
+ char *this_char, *value;
+
+ *uid = current->uid;
+ *gid = current->gid;
+ *pgrp = current->pgrp;
+
+ *minproto = *maxproto = AUTOFS_PROTO_VERSION;
+
+ *pipefd = -1;
+
+ if ( !options ) return 1;
+ for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+ if ((value = strchr(this_char,'=')) != NULL)
+ *value++ = 0;
+ if (!strcmp(this_char,"fd")) {
+ if (!value || !*value)
+ return 1;
+ *pipefd = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ }
+ else if (!strcmp(this_char,"uid")) {
+ if (!value || !*value)
+ return 1;
+ *uid = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ }
+ else if (!strcmp(this_char,"gid")) {
+ if (!value || !*value)
+ return 1;
+ *gid = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ }
+ else if (!strcmp(this_char,"pgrp")) {
+ if (!value || !*value)
+ return 1;
+ *pgrp = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ }
+ else if (!strcmp(this_char,"minproto")) {
+ if (!value || !*value)
+ return 1;
+ *minproto = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ }
+ else if (!strcmp(this_char,"maxproto")) {
+ if (!value || !*value)
+ return 1;
+ *maxproto = simple_strtoul(value,&value,0);
+ if (*value)
+ return 1;
+ }
+ else break;
+ }
+ return (*pipefd < 0);
+}
+
+static struct autofs_info *autofs4_mkroot(struct autofs_sb_info *sbi)
+{
+ struct autofs_info *ino;
+
+ ino = autofs4_init_ino(NULL, sbi, S_IFDIR | 0755);
+ if (!ino)
+ return NULL;
+
+ ino->ino = AUTOFS_ROOT_INO;
+
+ return ino;
+}
+
+struct super_block *autofs4_read_super(struct super_block *s, void *data,
+ int silent)
+{
+ struct inode * root_inode;
+ struct dentry * root;
+ struct file * pipe;
+ int pipefd;
+ struct autofs_sb_info *sbi;
+ int minproto, maxproto;
+
+ MOD_INC_USE_COUNT;
+
+ lock_super(s);
+ /* Super block already completed? */
+ if (s->s_root)
+ goto out_unlock;
+
+ sbi = (struct autofs_sb_info *) kmalloc(sizeof(*sbi), GFP_KERNEL);
+ if ( !sbi )
+ goto fail_unlock;
+ DPRINTK(("autofs: starting up, sbi = %p\n",sbi));
+
+ memset(sbi, 0, sizeof(*sbi));
+
+ s->u.generic_sbp = sbi;
+ sbi->magic = AUTOFS_SBI_MAGIC;
+ sbi->catatonic = 0;
+ sbi->exp_timeout = 0;
+ sbi->oz_pgrp = current->pgrp;
+ sbi->sb = s;
+ sbi->version = 0;
+ autofs4_init_ihash(&sbi->ihash);
+ sbi->queues = NULL;
+ sbi->next_ino = AUTOFS_FIRST_INO;
+ s->s_blocksize = 1024;
+ s->s_blocksize_bits = 10;
+ s->s_magic = AUTOFS_SUPER_MAGIC;
+ s->s_op = &autofs4_sops;
+ s->s_root = NULL;
+ unlock_super(s); /* shouldn't we keep it locked a while longer? */
+
+ /*
+ * Get the root inode and dentry, but defer checking for errors.
+ */
+ autofs4_ihash_insert(&sbi->ihash, autofs4_mkroot(sbi));
+
+ root_inode = iget(s, AUTOFS_ROOT_INO);
+ root = d_alloc_root(root_inode);
+ pipe = NULL;
+
+ /*
+ * Check whether somebody else completed the super block.
+ */
+ if (s->s_root)
+ goto out_dput;
+
+ if (!root)
+ goto fail_iput;
+
+ /* Can this call block? */
+ if (parse_options(data, &pipefd,
+ &root_inode->i_uid, &root_inode->i_gid,
+ &sbi->oz_pgrp,
+ &minproto, &maxproto)) {
+ printk("autofs: called with bogus options\n");
+ goto fail_dput;
+ }
+
+ /* Couldn't this be tested earlier? */
+ if (maxproto < AUTOFS_MIN_PROTO_VERSION ||
+ minproto > AUTOFS_PROTO_VERSION) {
+ printk("autofs: kernel does not match daemon version "
+ "daemon (%d, %d) kernel (%d, %d)\n",
+ minproto, maxproto,
+ AUTOFS_MIN_PROTO_VERSION, AUTOFS_PROTO_VERSION);
+ goto fail_dput;
+ }
+
+ sbi->version = maxproto > AUTOFS_PROTO_VERSION ? AUTOFS_PROTO_VERSION : maxproto;
+
+ DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp));
+ pipe = fget(pipefd);
+ /*
+ * Check whether somebody else completed the super block.
+ */
+ if (s->s_root)
+ goto out_fput;
+
+ if ( !pipe ) {
+ printk("autofs: could not open pipe file descriptor\n");
+ goto fail_dput;
+ }
+ if ( !pipe->f_op || !pipe->f_op->write )
+ goto fail_fput;
+ sbi->pipe = pipe;
+
+ /*
+ * Success! Install the root dentry now to indicate completion.
+ */
+ s->s_root = root;
+ return s;
+
+ /*
+ * Success ... somebody else completed the super block for us.
+ */
+out_unlock:
+ unlock_super(s);
+ goto out_dec;
+out_fput:
+ if (pipe)
+ fput(pipe);
+out_dput:
+ if (root)
+ dput(root);
+ else
+ iput(root_inode);
+out_dec:
+ MOD_DEC_USE_COUNT;
+ return s;
+
+ /*
+ * Failure ... clear the s_dev slot and clean up.
+ */
+fail_fput:
+ printk("autofs: pipe file descriptor does not contain proper ops\n");
+ /*
+ * fput() can block, so we clear the super block first.
+ */
+ s->s_dev = 0;
+ fput(pipe);
+ /* fall through */
+fail_dput:
+ /*
+ * dput() can block, so we clear the super block first.
+ */
+ s->s_dev = 0;
+ dput(root);
+ goto fail_free;
+fail_iput:
+ printk("autofs: get root dentry failed\n");
+ /*
+ * iput() can block, so we clear the super block first.
+ */
+ s->s_dev = 0;
+ iput(root_inode);
+fail_free:
+ kfree(sbi);
+ goto fail_dec;
+fail_unlock:
+ unlock_super(s);
+fail_dec:
+ s->s_dev = 0;
+ MOD_DEC_USE_COUNT;
+ return NULL;
+}
+
+static int autofs4_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+{
+ struct statfs tmp;
+
+ tmp.f_type = AUTOFS_SUPER_MAGIC;
+ tmp.f_bsize = 1024;
+ tmp.f_blocks = 0;
+ tmp.f_bfree = 0;
+ tmp.f_bavail = 0;
+ tmp.f_files = 0;
+ tmp.f_ffree = 0;
+ tmp.f_namelen = NAME_MAX;
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+}
+
+static void autofs4_read_inode(struct inode *inode)
+{
+ struct autofs_sb_info *sbi = autofs4_sbi(inode->i_sb);
+ struct autofs_info *inf;
+
+ inf = autofs4_ihash_find(&sbi->ihash, inode->i_ino);
+
+ if (inf == NULL || inf->inode != NULL)
+ return;
+
+ inode->i_mode = inf->mode;
+ inode->i_mtime = inode->i_ctime = inode->i_atime = CURRENT_TIME;
+ inode->i_size = inf->size;
+
+ inode->i_blocks = 0;
+ inode->i_blksize = 0;
+ inode->i_nlink = 1;
+
+ if (inode->i_sb->s_root) {
+ inode->i_uid = inode->i_sb->s_root->d_inode->i_uid;
+ inode->i_gid = inode->i_sb->s_root->d_inode->i_gid;
+ } else {
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ }
+
+ inf->inode = inode;
+
+ if (S_ISDIR(inf->mode)) {
+ inode->i_nlink = 2;
+ if (inode->i_ino == AUTOFS_ROOT_INO)
+ inode->i_op = &autofs4_root_inode_operations;
+ else
+ inode->i_op = &autofs4_dir_inode_operations;
+ } else if (S_ISLNK(inf->mode)) {
+ inode->i_op = &autofs4_symlink_inode_operations;
+ }
+}
+
+static void autofs4_write_inode(struct inode *inode)
+{
+}
diff --git a/fs/autofs4/inohash.c b/fs/autofs4/inohash.c
new file mode 100644
index 000000000..6190a55d3
--- /dev/null
+++ b/fs/autofs4/inohash.c
@@ -0,0 +1,68 @@
+/*
+ * "inohash" is a misnomer. Inodes are just stored in a single list,
+ * since this code is only ever asked for the most recently inserted
+ * inode.
+ *
+ * Copyright 1999 Jeremy Fitzhardinge <jeremy@goop.org>
+ */
+
+#include "autofs_i.h"
+
+void autofs4_init_ihash(struct autofs_inohash *ih)
+{
+ INIT_LIST_HEAD(&ih->head);
+}
+
+void autofs4_ihash_insert(struct autofs_inohash *ih,
+ struct autofs_info *ino)
+{
+ DPRINTK(("autofs_ihash_insert: adding ino %ld\n", ino->ino));
+
+ list_add(&ino->ino_hash, &ih->head);
+}
+
+void autofs4_ihash_delete(struct autofs_info *inf)
+{
+ DPRINTK(("autofs_ihash_delete: deleting ino %ld\n", inf->ino));
+
+ if (!list_empty(&inf->ino_hash))
+ list_del(&inf->ino_hash);
+}
+
+struct autofs_info *autofs4_ihash_find(struct autofs_inohash *ih,
+ ino_t inum)
+{
+ struct list_head *tmp;
+
+ for(tmp = ih->head.next;
+ tmp != &ih->head;
+ tmp = tmp->next) {
+ struct autofs_info *ino = list_entry(tmp, struct autofs_info, ino_hash);
+ if (ino->ino == inum) {
+ DPRINTK(("autofs_ihash_find: found %ld -> %p\n",
+ inum, ino));
+ return ino;
+ }
+ }
+ DPRINTK(("autofs_ihash_find: didn't find %ld\n", inum));
+ return NULL;
+}
+
+void autofs4_ihash_nuke(struct autofs_inohash *ih)
+{
+ struct list_head *tmp = ih->head.next;
+ struct list_head *next;
+
+ for(; tmp != &ih->head; tmp = next) {
+ struct autofs_info *ino;
+
+ next = tmp->next;
+
+ ino = list_entry(tmp, struct autofs_info, ino_hash);
+
+ DPRINTK(("autofs_ihash_nuke: nuking %ld\n", ino->ino));
+ autofs4_free_ino(ino);
+ }
+ INIT_LIST_HEAD(&ih->head);
+}
+
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
new file mode 100644
index 000000000..b7e4bcd0c
--- /dev/null
+++ b/fs/autofs4/root.c
@@ -0,0 +1,624 @@
+/* -*- linux-c -*- --------------------------------------------------------- *
+ *
+ * linux/fs/autofs/root.c
+ *
+ * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
+ * Copyright 1999 Jeremy Fitzhardinge <jeremy@goop.org>
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+
+#include <linux/errno.h>
+#include <linux/stat.h>
+#include <linux/param.h>
+#include "autofs_i.h"
+
+static int autofs4_dir_readdir(struct file *,void *,filldir_t);
+static struct dentry *autofs4_dir_lookup(struct inode *,struct dentry *);
+static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *);
+static int autofs4_dir_unlink(struct inode *,struct dentry *);
+static int autofs4_dir_rmdir(struct inode *,struct dentry *);
+static int autofs4_dir_mkdir(struct inode *,struct dentry *,int);
+static int autofs4_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
+static struct dentry *autofs4_root_lookup(struct inode *,struct dentry *);
+
+static struct file_operations autofs4_root_operations = {
+ readdir: autofs4_dir_readdir, /* readdir */
+ ioctl: autofs4_root_ioctl, /* ioctl */
+};
+
+struct inode_operations autofs4_root_inode_operations = {
+ &autofs4_root_operations, /* file operations */
+
+ lookup: autofs4_root_lookup, /* lookup */
+ unlink: autofs4_dir_unlink, /* unlink */
+ symlink: autofs4_dir_symlink, /* symlink */
+ mkdir: autofs4_dir_mkdir, /* mkdir */
+ rmdir: autofs4_dir_rmdir, /* rmdir */
+};
+
+static struct file_operations autofs4_dir_operations = {
+ readdir: autofs4_dir_readdir, /* readdir */
+};
+
+struct inode_operations autofs4_dir_inode_operations = {
+ &autofs4_dir_operations, /* file operations */
+
+ lookup: autofs4_dir_lookup, /* lookup */
+ unlink: autofs4_dir_unlink, /* unlink */
+ symlink: autofs4_dir_symlink, /* symlink */
+ mkdir: autofs4_dir_mkdir, /* mkdir */
+ rmdir: autofs4_dir_rmdir, /* rmdir */
+};
+
+static inline struct dentry *nth_child(struct dentry *dir, int nr)
+{
+ struct list_head *tmp = dir->d_subdirs.next;
+
+ while(tmp != &dir->d_subdirs) {
+ if (nr-- == 0)
+ return list_entry(tmp, struct dentry, d_child);
+ tmp = tmp->next;
+ }
+ return NULL;
+}
+
+static int autofs4_dir_readdir(struct file *filp, void *dirent,
+ filldir_t filldir)
+{
+ struct autofs_sb_info *sbi;
+ struct autofs_info *ino;
+ struct dentry *dentry = filp->f_dentry;
+ struct dentry *dent_ptr;
+ struct inode *dir = dentry->d_inode;
+ struct list_head *cursor;
+ off_t nr;
+
+ sbi = autofs4_sbi(dir->i_sb);
+ ino = autofs4_dentry_ino(dentry);
+ nr = filp->f_pos;
+
+ switch(nr)
+ {
+ case 0:
+ if (filldir(dirent, ".", 1, nr, dir->i_ino) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ case 1:
+ if (filldir(dirent, "..", 2, nr, dentry->d_covers->d_parent->d_inode->i_ino) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ default:
+ dent_ptr = nth_child(dentry, nr-2);
+ if (dent_ptr == NULL)
+ break;
+
+ cursor = &dent_ptr->d_child;
+
+ while(cursor != &dentry->d_subdirs) {
+ dent_ptr = list_entry(cursor, struct dentry, d_child);
+ if (dent_ptr->d_inode &&
+ filldir(dirent, dent_ptr->d_name.name, dent_ptr->d_name.len, nr,
+ dent_ptr->d_inode->i_ino) < 0)
+ return 0;
+ filp->f_pos = ++nr;
+ cursor = cursor->next;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/* Update usage from here to top of tree, so that scan of
+ top-level directories will give a useful result */
+static void autofs4_update_usage(struct dentry *dentry)
+{
+ struct dentry *top = dentry->d_sb->s_root;
+
+ for(; dentry != top; dentry = dentry->d_parent) {
+ struct autofs_info *ino = autofs4_dentry_ino(dentry->d_covers);
+
+ if (ino) {
+ update_atime(dentry->d_inode);
+ ino->last_used = jiffies;
+ }
+ }
+}
+
+static int try_to_fill_dentry(struct dentry *dentry,
+ struct super_block *sb,
+ struct autofs_sb_info *sbi)
+{
+ struct autofs_info *de_info = autofs4_dentry_ino(dentry);
+ int status = 0;
+
+ /* Block on any pending expiry here; invalidate the dentry
+ when expiration is done to trigger mount request with a new
+ dentry */
+ if (de_info && (de_info->flags & AUTOFS_INF_EXPIRING)) {
+ DPRINTK(("try_to_fill_entry: waiting for expire %p name=%.*s, flags&PENDING=%s de_info=%p de_info->flags=%x\n",
+ dentry, dentry->d_name.len, dentry->d_name.name,
+ dentry->d_flags & DCACHE_AUTOFS_PENDING?"t":"f",
+ de_info, de_info?de_info->flags:0));
+ status = autofs4_wait(sbi, &dentry->d_name, NFY_NONE);
+
+ DPRINTK(("try_to_fill_entry: expire done status=%d\n", status));
+
+ return 0;
+ }
+
+ DPRINTK(("try_to_fill_entry: dentry=%p %.*s ino=%p\n",
+ dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode));
+
+ /* Wait for a pending mount, triggering one if there isn't one already */
+ while(dentry->d_inode == NULL) {
+ DPRINTK(("try_to_fill_entry: waiting for mount name=%.*s, de_info=%p de_info->flags=%x\n",
+ dentry->d_name.len, dentry->d_name.name,
+ de_info, de_info?de_info->flags:0));
+ status = autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT);
+
+ DPRINTK(("try_to_fill_entry: mount done status=%d\n", status));
+
+ if (status && dentry->d_inode)
+ return 0; /* Try to get the kernel to invalidate this dentry */
+
+ /* Turn this into a real negative dentry? */
+ if (status == -ENOENT) {
+ dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT;
+ dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
+ return 1;
+ } else if (status) {
+ /* Return a negative dentry, but leave it "pending" */
+ return 1;
+ }
+ status = autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT);
+ }
+
+ /* If this is an unused directory that isn't a mount point,
+ bitch at the daemon and fix it in user space */
+ if (S_ISDIR(dentry->d_inode->i_mode) &&
+ dentry->d_mounts == dentry &&
+ list_empty(&dentry->d_subdirs)) {
+ DPRINTK(("try_to_fill_entry: mounting existing dir\n"));
+ return autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT) == 0;
+ }
+
+ /* We don't update the usages for the autofs daemon itself, this
+ is necessary for recursive autofs mounts */
+ if (!autofs4_oz_mode(sbi))
+ autofs4_update_usage(dentry);
+
+ dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
+ return 1;
+}
+
+
+/*
+ * Revalidate is called on every cache lookup. Some of those
+ * cache lookups may actually happen while the dentry is not
+ * yet completely filled in, and revalidate has to delay such
+ * lookups..
+ */
+static int autofs4_root_revalidate(struct dentry * dentry, int flags)
+{
+ struct inode * dir = dentry->d_parent->d_inode;
+ struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
+ struct autofs_info *ino;
+ int oz_mode = autofs4_oz_mode(sbi);
+
+ /* Pending dentry */
+ if (autofs4_ispending(dentry)) {
+ if (autofs4_oz_mode(sbi))
+ return 1;
+ else
+ return try_to_fill_dentry(dentry, dir->i_sb, sbi);
+ }
+
+ /* Negative dentry.. invalidate if "old" */
+ if (dentry->d_inode == NULL)
+ return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT);
+
+ ino = autofs4_dentry_ino(dentry);
+
+ /* Check for a non-mountpoint directory with no contents */
+ if (S_ISDIR(dentry->d_inode->i_mode) &&
+ dentry->d_mounts == dentry &&
+ list_empty(&dentry->d_subdirs)) {
+ DPRINTK(("autofs_root_revalidate: dentry=%p %.*s, emptydir\n",
+ dentry, dentry->d_name.len, dentry->d_name.name));
+ if (autofs4_oz_mode(sbi))
+ return 1;
+ else
+ return try_to_fill_dentry(dentry, dir->i_sb, sbi);
+ }
+
+ /* Update the usage list */
+ if (!oz_mode)
+ autofs4_update_usage(dentry);
+
+ return 1;
+}
+
+static int autofs4_revalidate(struct dentry *dentry, int flags)
+{
+ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+
+ if (!autofs4_oz_mode(sbi))
+ autofs4_update_usage(dentry);
+
+ return 1;
+}
+
+static void autofs4_dentry_release(struct dentry *de)
+{
+ struct autofs_info *inf = autofs4_dentry_ino(de);
+
+ DPRINTK(("autofs4_dentry_release: releasing %p\n", de));
+
+ de->d_fsdata = NULL;
+ if (inf) {
+ inf->dentry = NULL;
+ inf->inode = NULL;
+
+ autofs4_free_ino(inf);
+ }
+}
+
+/* For dentries of directories in the root dir */
+static struct dentry_operations autofs4_root_dentry_operations = {
+ d_revalidate: autofs4_root_revalidate, /* d_revalidate */
+ d_release: autofs4_dentry_release,
+};
+
+/* For other dentries */
+static struct dentry_operations autofs4_dentry_operations = {
+ d_revalidate: autofs4_revalidate, /* d_revalidate */
+ d_release: autofs4_dentry_release,
+};
+
+/* Lookups in non-root dirs never find anything - if it's there, it's
+ already in the dcache */
+static struct dentry *autofs4_dir_lookup(struct inode *dir, struct dentry *dentry)
+{
+#if 0
+ DPRINTK(("autofs_dir_lookup: ignoring lookup of %.*s/%.*s\n",
+ dentry->d_parent->d_name.len, dentry->d_parent->d_name.name,
+ dentry->d_name.len, dentry->d_name.name));
+#endif
+
+ dentry->d_fsdata = NULL;
+ d_add(dentry, NULL);
+ return NULL;
+}
+
+/* Lookups in the root directory */
+static struct dentry *autofs4_root_lookup(struct inode *dir, struct dentry *dentry)
+{
+ struct autofs_sb_info *sbi;
+ int oz_mode;
+
+ DPRINTK(("autofs_root_lookup: name = %.*s\n",
+ dentry->d_name.len, dentry->d_name.name));
+
+ if (dentry->d_name.len > NAME_MAX)
+ return ERR_PTR(-ENOENT);/* File name too long to exist */
+
+ sbi = autofs4_sbi(dir->i_sb);
+
+ oz_mode = autofs4_oz_mode(sbi);
+ DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n",
+ current->pid, current->pgrp, sbi->catatonic, oz_mode));
+
+ /*
+ * Mark the dentry incomplete, but add it. This is needed so
+ * that the VFS layer knows about the dentry, and we can count
+ * on catching any lookups through the revalidate.
+ *
+ * Let all the hard work be done by the revalidate function that
+ * needs to be able to do this anyway..
+ *
+ * We need to do this before we release the directory semaphore.
+ */
+ if (dir->i_ino == AUTOFS_ROOT_INO)
+ dentry->d_op = &autofs4_root_dentry_operations;
+ else
+ dentry->d_op = &autofs4_dentry_operations;
+
+ dentry->d_flags |= DCACHE_AUTOFS_PENDING;
+ dentry->d_fsdata = NULL;
+ d_add(dentry, NULL);
+
+ if (dentry->d_op && dentry->d_op->d_revalidate) {
+ up(&dir->i_sem);
+ (dentry->d_op->d_revalidate)(dentry, 0);
+ down(&dir->i_sem);
+ }
+
+ /*
+ * If we are still pending, check if we had to handle
+ * a signal. If so we can force a restart..
+ */
+ if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
+ if (signal_pending(current))
+ return ERR_PTR(-ERESTARTNOINTR);
+ }
+
+ /*
+ * If this dentry is unhashed, then we shouldn't honour this
+ * lookup even if the dentry is positive. Returning ENOENT here
+ * doesn't do the right thing for all system calls, but it should
+ * be OK for the operations we permit from an autofs.
+ */
+ if ( dentry->d_inode && list_empty(&dentry->d_hash) )
+ return ERR_PTR(-ENOENT);
+
+ return NULL;
+}
+
+static int autofs4_dir_symlink(struct inode *dir,
+ struct dentry *dentry,
+ const char *symname)
+{
+ struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
+ struct inode *inode;
+ char *cp;
+
+ DPRINTK(("autofs_dir_symlink: %s <- %.*s\n", symname,
+ dentry->d_name.len, dentry->d_name.name));
+
+ if (!S_ISDIR(dir->i_mode))
+ return -ENOTDIR;
+
+ if (!autofs4_oz_mode(sbi))
+ return -EACCES;
+
+ if (dentry->d_name.len > NAME_MAX)
+ return -ENAMETOOLONG;
+
+ if (dentry->d_inode != NULL)
+ return -EEXIST;
+
+ ino = autofs4_init_ino(ino, sbi, S_IFLNK | 0555);
+ if (ino == NULL)
+ return -ENOSPC;
+
+ ino->size = strlen(symname);
+ ino->u.symlink = cp = kmalloc(ino->size + 1, GFP_KERNEL);
+
+ if (cp == NULL) {
+ kfree(ino);
+ return -ENOSPC;
+ }
+
+ strcpy(cp, symname);
+
+ autofs4_ihash_insert(&sbi->ihash, ino);
+ inode = iget(dir->i_sb,ino->ino);
+ d_instantiate(dentry, inode);
+
+ if (dir->i_ino == AUTOFS_ROOT_INO)
+ dentry->d_op = &autofs4_root_dentry_operations;
+ else
+ dentry->d_op = &autofs4_dentry_operations;
+
+ dentry->d_fsdata = ino;
+ ino->dentry = dget(dentry);
+ ino->inode = inode;
+
+ dir->i_mtime = CURRENT_TIME;
+
+ return 0;
+}
+
+/*
+ * NOTE!
+ *
+ * Normal filesystems would do a "d_delete()" to tell the VFS dcache
+ * that the file no longer exists. However, doing that means that the
+ * VFS layer can turn the dentry into a negative dentry. We don't want
+ * this, because since the unlink is probably the result of an expire.
+ * We simply d_drop it, which allows the dentry lookup to remount it
+ * if necessary.
+ *
+ * If a process is blocked on the dentry waiting for the expire to finish,
+ * it will invalidate the dentry and try to mount with a new one.
+ *
+ * Also see autofs_dir_rmdir()..
+ */
+static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
+
+ if (!S_ISDIR(dir->i_mode))
+ return -ENOTDIR;
+
+ if (dentry->d_inode == NULL)
+ return -ENOENT;
+
+ /* This allows root to remove symlinks */
+ if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+ return -EACCES;
+
+ dput(ino->dentry);
+
+ dentry->d_inode->i_size = 0;
+ dentry->d_inode->i_nlink = 0;
+
+ dir->i_mtime = CURRENT_TIME;
+
+ DPRINTK(("autofs_dir_unlink: unlinking %p %.*s, count=%d\n",
+ dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_count));
+
+ d_drop(dentry);
+
+ return 0;
+}
+
+static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
+
+ if (!S_ISDIR(dir->i_mode))
+ return -ENOTDIR;
+
+ if (dentry->d_inode == NULL)
+ return -ENOENT;
+
+ if (!autofs4_oz_mode(sbi))
+ return -EACCES;
+
+ if (!list_empty(&dentry->d_subdirs))
+ return -ENOTEMPTY;
+
+ dput(ino->dentry);
+
+ dentry->d_inode->i_size = 0;
+ dentry->d_inode->i_nlink = 0;
+
+ if (dir->i_nlink)
+ dir->i_nlink--;
+
+ DPRINTK(("autofs_dir_rmdir: rmdir %p %.*s, count=%d\n",
+ dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_count));
+
+ d_drop(dentry);
+
+ return 0;
+}
+
+
+
+static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+ struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
+ struct inode *inode;
+
+ if (!S_ISDIR(dir->i_mode))
+ return -ENOTDIR;
+
+ if ( !autofs4_oz_mode(sbi) )
+ return -EACCES;
+
+ if ( dentry->d_inode != NULL )
+ return -EEXIST;
+
+ if ( dentry->d_name.len > NAME_MAX )
+ return -ENAMETOOLONG;
+
+ DPRINTK(("autofs_dir_mkdir: dentry %p, creating %.*s\n",
+ dentry, dentry->d_name.len, dentry->d_name.name));
+
+ ino = autofs4_init_ino(ino, sbi, S_IFDIR | 0555);
+ if (ino == NULL)
+ return -ENOSPC;
+
+ autofs4_ihash_insert(&sbi->ihash, ino);
+
+ inode = iget(dir->i_sb, ino->ino);
+ d_instantiate(dentry, inode);
+
+ if (dir->i_ino == AUTOFS_ROOT_INO)
+ dentry->d_op = &autofs4_root_dentry_operations;
+ else
+ dentry->d_op = &autofs4_dentry_operations;
+
+ dentry->d_fsdata = ino;
+ ino->dentry = dget(dentry);
+ ino->inode = inode;
+ dir->i_nlink++;
+ dir->i_mtime = CURRENT_TIME;
+
+ return 0;
+}
+
+/* Get/set timeout ioctl() operation */
+static inline int autofs4_get_set_timeout(struct autofs_sb_info *sbi,
+ unsigned long *p)
+{
+ int rv;
+ unsigned long ntimeout;
+
+ if ( (rv = get_user(ntimeout, p)) ||
+ (rv = put_user(sbi->exp_timeout/HZ, p)) )
+ return rv;
+
+ if ( ntimeout > ULONG_MAX/HZ )
+ sbi->exp_timeout = 0;
+ else
+ sbi->exp_timeout = ntimeout * HZ;
+
+ return 0;
+}
+
+/* Return protocol version */
+static inline int autofs4_get_protover(struct autofs_sb_info *sbi, int *p)
+{
+ return put_user(sbi->version, p);
+}
+
+/* Identify autofs_dentries - this is so we can tell if there's
+ an extra dentry refcount or not. We only hold a refcount on the
+ dentry if its non-negative (ie, d_inode != NULL)
+*/
+int is_autofs4_dentry(struct dentry *dentry)
+{
+ return dentry && dentry->d_inode &&
+ (dentry->d_op == &autofs4_root_dentry_operations ||
+ dentry->d_op == &autofs4_dentry_operations) &&
+ dentry->d_fsdata != NULL;
+}
+
+/*
+ * ioctl()'s on the root directory is the chief method for the daemon to
+ * generate kernel reactions
+ */
+static int autofs4_root_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct autofs_sb_info *sbi = autofs4_sbi(inode->i_sb);
+
+ DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",
+ cmd,arg,sbi,current->pgrp));
+
+ if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
+ _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
+ return -ENOTTY;
+
+ if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+ return -EPERM;
+
+ switch(cmd) {
+ case AUTOFS_IOC_READY: /* Wait queue: go ahead and retry */
+ return autofs4_wait_release(sbi,(autofs_wqt_t)arg,0);
+ case AUTOFS_IOC_FAIL: /* Wait queue: fail with ENOENT */
+ return autofs4_wait_release(sbi,(autofs_wqt_t)arg,-ENOENT);
+ case AUTOFS_IOC_CATATONIC: /* Enter catatonic mode (daemon shutdown) */
+ autofs4_catatonic_mode(sbi);
+ return 0;
+ case AUTOFS_IOC_PROTOVER: /* Get protocol version */
+ return autofs4_get_protover(sbi, (int *)arg);
+ case AUTOFS_IOC_SETTIMEOUT:
+ return autofs4_get_set_timeout(sbi,(unsigned long *)arg);
+
+ /* return a single thing to expire */
+ case AUTOFS_IOC_EXPIRE:
+ return autofs4_expire_run(inode->i_sb,sbi,
+ (struct autofs_packet_expire *)arg);
+ /* same as above, but can send multiple expires through pipe */
+ case AUTOFS_IOC_EXPIRE_MULTI:
+ return autofs4_expire_multi(inode->i_sb, sbi, (int *)arg);
+
+ default:
+ return -ENOSYS;
+ }
+}
diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c
new file mode 100644
index 000000000..b86b400cf
--- /dev/null
+++ b/fs/autofs4/symlink.c
@@ -0,0 +1,34 @@
+/* -*- linux-c -*- --------------------------------------------------------- *
+ *
+ * linux/fs/autofs/symlink.c
+ *
+ * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+
+#include "autofs_i.h"
+
+static int autofs4_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
+
+ return vfs_readlink(dentry, buffer, buflen, ino->u.symlink);
+}
+
+static struct dentry * autofs4_follow_link(struct dentry *dentry,
+ struct dentry *base,
+ unsigned int flags)
+{
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
+
+ return vfs_follow_link(dentry, base, flags, ino->u.symlink);
+}
+
+struct inode_operations autofs4_symlink_inode_operations = {
+ readlink: autofs4_readlink,
+ follow_link: autofs4_follow_link
+};
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
new file mode 100644
index 000000000..464c940b8
--- /dev/null
+++ b/fs/autofs4/waitq.c
@@ -0,0 +1,251 @@
+/* -*- linux-c -*- --------------------------------------------------------- *
+ *
+ * linux/fs/autofs/waitq.c
+ *
+ * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * ------------------------------------------------------------------------- */
+
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/file.h>
+#include "autofs_i.h"
+
+/* We make this a static variable rather than a part of the superblock; it
+ is better if we don't reassign numbers easily even across filesystems */
+static autofs_wqt_t autofs4_next_wait_queue = 1;
+
+/* These are the signals we allow interrupting a pending mount */
+#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT))
+
+void autofs4_catatonic_mode(struct autofs_sb_info *sbi)
+{
+ struct autofs_wait_queue *wq, *nwq;
+
+ DPRINTK(("autofs: entering catatonic mode\n"));
+
+ sbi->catatonic = 1;
+ wq = sbi->queues;
+ sbi->queues = NULL; /* Erase all wait queues */
+ while ( wq ) {
+ nwq = wq->next;
+ wq->status = -ENOENT; /* Magic is gone - report failure */
+ kfree(wq->name);
+ wq->name = NULL;
+ wake_up(&wq->queue);
+ wq = nwq;
+ }
+ if (sbi->pipe) {
+ fput(sbi->pipe); /* Close the pipe */
+ sbi->pipe = NULL;
+ }
+
+ autofs4_ihash_nuke(&sbi->ihash);
+ shrink_dcache_sb(sbi->sb);
+}
+
+static int autofs4_write(struct file *file, const void *addr, int bytes)
+{
+ unsigned long sigpipe, flags;
+ mm_segment_t fs;
+ const char *data = (const char *)addr;
+ ssize_t wr = 0;
+
+ /** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/
+
+ sigpipe = sigismember(&current->signal, SIGPIPE);
+
+ /* Save pointer to user space and point back to kernel space */
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ while (bytes &&
+ (wr = file->f_op->write(file,data,bytes,&file->f_pos)) > 0) {
+ data += wr;
+ bytes -= wr;
+ }
+
+ set_fs(fs);
+
+ /* Keep the currently executing process from receiving a
+ SIGPIPE unless it was already supposed to get one */
+ if (wr == -EPIPE && !sigpipe) {
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ sigdelset(&current->signal, SIGPIPE);
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
+ }
+
+ return (bytes > 0);
+}
+
+static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
+ struct autofs_wait_queue *wq,
+ enum autofs_packet_type type)
+{
+ union autofs_packet_union pkt;
+ size_t pktsz;
+
+ DPRINTK(("autofs_notify: wait id = 0x%08lx, name = %.*s, type=%d\n",
+ wq->wait_queue_token, wq->len, wq->name, type));
+
+ memset(&pkt,0,sizeof pkt); /* For security reasons */
+
+ pkt.hdr.proto_version = sbi->version;
+ pkt.hdr.type = type;
+ if (type == autofs_ptype_missing) {
+ struct autofs_packet_missing *mp = &pkt.missing;
+
+ pktsz = sizeof(*mp);
+
+ mp->wait_queue_token = wq->wait_queue_token;
+ mp->len = wq->len;
+ memcpy(mp->name, wq->name, wq->len);
+ mp->name[wq->len] = '\0';
+ } else if (type == autofs_ptype_expire_multi) {
+ struct autofs_packet_expire_multi *ep = &pkt.expire_multi;
+
+ pktsz = sizeof(*ep);
+
+ ep->wait_queue_token = wq->wait_queue_token;
+ ep->len = wq->len;
+ memcpy(ep->name, wq->name, wq->len);
+ ep->name[wq->len] = '\0';
+ } else {
+ printk("autofs_notify_daemon: bad type %d!\n", type);
+ return;
+ }
+
+ if (autofs4_write(sbi->pipe, &pkt, pktsz))
+ autofs4_catatonic_mode(sbi);
+}
+
+int autofs4_wait(struct autofs_sb_info *sbi, struct qstr *name,
+ enum autofs_notify notify)
+{
+ struct autofs_wait_queue *wq;
+ int status;
+
+ /* In catatonic mode, we don't wait for nobody */
+ if ( sbi->catatonic )
+ return -ENOENT;
+
+ /* We shouldn't be able to get here, but just in case */
+ if ( name->len > NAME_MAX )
+ return -ENOENT;
+
+ for ( wq = sbi->queues ; wq ; wq = wq->next ) {
+ if ( wq->hash == name->hash &&
+ wq->len == name->len &&
+ wq->name && !memcmp(wq->name,name->name,name->len) )
+ break;
+ }
+
+ if ( !wq ) {
+ /* Create a new wait queue */
+ wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL);
+ if ( !wq )
+ return -ENOMEM;
+
+ wq->name = kmalloc(name->len,GFP_KERNEL);
+ if ( !wq->name ) {
+ kfree(wq);
+ return -ENOMEM;
+ }
+ wq->wait_queue_token = autofs4_next_wait_queue;
+ if (++autofs4_next_wait_queue == 0)
+ autofs4_next_wait_queue = 1;
+ init_waitqueue_head(&wq->queue);
+ wq->hash = name->hash;
+ wq->len = name->len;
+ wq->status = -EINTR; /* Status return if interrupted */
+ memcpy(wq->name, name->name, name->len);
+ wq->next = sbi->queues;
+ sbi->queues = wq;
+
+ DPRINTK(("autofs_wait: new wait id = 0x%08lx, name = %.*s, nfy=%d\n",
+ wq->wait_queue_token, wq->len, wq->name, notify));
+ /* autofs4_notify_daemon() may block */
+ wq->wait_ctr = 2;
+ if (notify != NFY_NONE) {
+ autofs4_notify_daemon(sbi,wq,
+ notify == NFY_MOUNT ? autofs_ptype_missing :
+ autofs_ptype_expire_multi);
+ }
+ } else {
+ wq->wait_ctr++;
+ DPRINTK(("autofs_wait: existing wait id = 0x%08lx, name = %.*s, nfy=%d\n",
+ wq->wait_queue_token, wq->len, wq->name, notify));
+ }
+
+ /* wq->name is NULL if and only if the lock is already released */
+
+ if ( sbi->catatonic ) {
+ /* We might have slept, so check again for catatonic mode */
+ wq->status = -ENOENT;
+ if ( wq->name ) {
+ kfree(wq->name);
+ wq->name = NULL;
+ }
+ }
+
+ if ( wq->name ) {
+ /* Block all but "shutdown" signals while waiting */
+ sigset_t oldset;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&current->sigmask_lock, irqflags);
+ oldset = current->blocked;
+ siginitsetinv(&current->blocked, SHUTDOWN_SIGS & ~oldset.sig[0]);
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
+
+ interruptible_sleep_on(&wq->queue);
+
+ spin_lock_irqsave(&current->sigmask_lock, irqflags);
+ current->blocked = oldset;
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
+ } else {
+ DPRINTK(("autofs_wait: skipped sleeping\n"));
+ }
+
+ status = wq->status;
+
+ if (--wq->wait_ctr == 0) /* Are we the last process to need status? */
+ kfree(wq);
+
+ return status;
+}
+
+
+int autofs4_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_token, int status)
+{
+ struct autofs_wait_queue *wq, **wql;
+
+ for ( wql = &sbi->queues ; (wq = *wql) ; wql = &wq->next ) {
+ if ( wq->wait_queue_token == wait_queue_token )
+ break;
+ }
+ if ( !wq )
+ return -EINVAL;
+
+ *wql = wq->next; /* Unlink from chain */
+ kfree(wq->name);
+ wq->name = NULL; /* Do not wait on this queue */
+
+ wq->status = status;
+
+ if (--wq->wait_ctr == 0) /* Is anyone still waiting for this guy? */
+ kfree(wq);
+ else
+ wake_up(&wq->queue);
+
+ return 0;
+}
+
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 0e34b95bd..47362da04 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -652,7 +652,7 @@ struct inode_operations blkdev_inode_operations = {
&def_blk_fops, /* default file operations */
};
-char * bdevname(kdev_t dev)
+const char * bdevname(kdev_t dev)
{
static char buffer[32];
const char * name = blkdevs[MAJOR(dev)].name;
diff --git a/fs/dcache.c b/fs/dcache.c
index a9a81328a..dc424305f 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -412,20 +412,18 @@ void shrink_dcache_parent(struct dentry * parent)
*/
int shrink_dcache_memory(int priority, unsigned int gfp_mask, zone_t * zone)
{
- if (gfp_mask & __GFP_IO) {
- int count = 0;
- lock_kernel();
- if (priority)
- count = dentry_stat.nr_unused / priority;
- prune_dcache(count);
- unlock_kernel();
- /* FIXME: kmem_cache_shrink here should tell us
- the number of pages freed, and it should
- work in a __GFP_DMA/__GFP_HIGHMEM behaviour
- to free only the interesting pages in
- function of the needs of the current allocation. */
- kmem_cache_shrink(dentry_cache);
- }
+ int count = 0;
+ lock_kernel();
+ if (priority)
+ count = dentry_stat.nr_unused / priority;
+ prune_dcache(count);
+ unlock_kernel();
+ /* FIXME: kmem_cache_shrink here should tell us
+ the number of pages freed, and it should
+ work in a __GFP_DMA/__GFP_HIGHMEM behaviour
+ to free only the interesting pages in
+ function of the needs of the current allocation. */
+ kmem_cache_shrink(dentry_cache);
return 0;
}
diff --git a/fs/devices.c b/fs/devices.c
index 3efb5822a..36e15475a 100644
--- a/fs/devices.c
+++ b/fs/devices.c
@@ -168,14 +168,14 @@ static struct inode_operations chrdev_inode_operations = {
* Print device name (in decimal, hexadecimal or symbolic)
* Note: returns pointer to static data!
*/
-char * kdevname(kdev_t dev)
+const char * kdevname(kdev_t dev)
{
static char buffer[32];
sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
return buffer;
}
-char * cdevname(kdev_t dev)
+const char * cdevname(kdev_t dev)
{
static char buffer[32];
const char * name = chrdevs[MAJOR(dev)].name;
diff --git a/fs/dquot.c b/fs/dquot.c
index 1efafcf51..61dcef366 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -797,17 +797,22 @@ static inline int need_print_warning(struct dquot *dquot, int flag)
return 0;
}
-static void print_warning(struct dquot *dquot, int flag, char *fmtstr, ...)
+static void print_warning(struct dquot *dquot, int flag, const char *fmtstr)
{
- va_list args;
+ struct dentry *root;
+ char *path, *buffer;
if (!need_print_warning(dquot, flag))
return;
- va_start(args, fmtstr);
- vsprintf(quotamessage, fmtstr, args);
- va_end(args);
+ root = dquot->dq_mnt->mnt_sb->s_root;
+ dget(root);
+ buffer = (char *) __get_free_page(GFP_KERNEL);
+ path = buffer ? d_path(root, buffer, PAGE_SIZE) : "?";
+ sprintf(quotamessage, fmtstr, path, quotatypes[dquot->dq_type]);
+ free_page((unsigned long) buffer);
tty_write_message(current->tty, quotamessage);
dquot->dq_flags |= flag;
+ dput(root);
}
static inline char ignore_hardlimit(struct dquot *dquot)
@@ -817,16 +822,13 @@ static inline char ignore_hardlimit(struct dquot *dquot)
static int check_idq(struct dquot *dquot, u_long inodes)
{
- short type = dquot->dq_type;
-
if (inodes <= 0 || dquot->dq_flags & DQ_FAKE)
return QUOTA_OK;
if (dquot->dq_ihardlimit &&
(dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit &&
!ignore_hardlimit(dquot)) {
- print_warning(dquot, DQ_INODES, "%s: write failed, %s file limit reached\n",
- dquot->dq_mnt->mnt_dirname, quotatypes[type]);
+ print_warning(dquot, DQ_INODES, "%s: write failed, %s file limit reached\n");
return NO_QUOTA;
}
@@ -834,17 +836,15 @@ static int check_idq(struct dquot *dquot, u_long inodes)
(dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime &&
!ignore_hardlimit(dquot)) {
- print_warning(dquot, DQ_INODES, "%s: warning, %s file quota exceeded too long.\n",
- dquot->dq_mnt->mnt_dirname, quotatypes[type]);
+ print_warning(dquot, DQ_INODES, "%s: warning, %s file quota exceeded too long.\n");
return NO_QUOTA;
}
if (dquot->dq_isoftlimit &&
(dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
dquot->dq_itime == 0) {
- print_warning(dquot, 0, "%s: warning, %s file quota exceeded\n",
- dquot->dq_mnt->mnt_dirname, quotatypes[type]);
- dquot->dq_itime = CURRENT_TIME + dquot->dq_mnt->mnt_dquot.inode_expire[type];
+ print_warning(dquot, 0, "%s: warning, %s file quota exceeded\n");
+ dquot->dq_itime = CURRENT_TIME + dquot->dq_mnt->mnt_dquot.inode_expire[dquot->dq_type];
}
return QUOTA_OK;
@@ -852,8 +852,6 @@ static int check_idq(struct dquot *dquot, u_long inodes)
static int check_bdq(struct dquot *dquot, u_long blocks, char prealloc)
{
- short type = dquot->dq_type;
-
if (blocks <= 0 || dquot->dq_flags & DQ_FAKE)
return QUOTA_OK;
@@ -861,8 +859,7 @@ static int check_bdq(struct dquot *dquot, u_long blocks, char prealloc)
(dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit &&
!ignore_hardlimit(dquot)) {
if (!prealloc)
- print_warning(dquot, DQ_BLKS, "%s: write failed, %s disk limit reached.\n",
- dquot->dq_mnt->mnt_dirname, quotatypes[type]);
+ print_warning(dquot, DQ_BLKS, "%s: write failed, %s disk limit reached.\n");
return NO_QUOTA;
}
@@ -871,8 +868,7 @@ static int check_bdq(struct dquot *dquot, u_long blocks, char prealloc)
dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime &&
!ignore_hardlimit(dquot)) {
if (!prealloc)
- print_warning(dquot, DQ_BLKS, "%s: write failed, %s disk quota exceeded too long.\n",
- dquot->dq_mnt->mnt_dirname, quotatypes[type]);
+ print_warning(dquot, DQ_BLKS, "%s: write failed, %s disk quota exceeded too long.\n");
return NO_QUOTA;
}
@@ -880,9 +876,8 @@ static int check_bdq(struct dquot *dquot, u_long blocks, char prealloc)
(dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&
dquot->dq_btime == 0) {
if (!prealloc) {
- print_warning(dquot, 0, "%s: warning, %s disk quota exceeded\n",
- dquot->dq_mnt->mnt_dirname, quotatypes[type]);
- dquot->dq_btime = CURRENT_TIME + dquot->dq_mnt->mnt_dquot.block_expire[type];
+ print_warning(dquot, 0, "%s: warning, %s disk quota exceeded\n");
+ dquot->dq_btime = CURRENT_TIME + dquot->dq_mnt->mnt_dquot.block_expire[dquot->dq_type];
}
else
/*
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 57a0be62d..08136962a 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -345,18 +345,20 @@ static inline void ext2_set_de_type(struct super_block *sb,
umode_t mode) {
if (!EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE))
return;
- if (S_ISCHR(mode))
+ if (S_ISREG(mode))
+ de->file_type = EXT2_FT_REG_FILE;
+ else if (S_ISDIR(mode))
+ de->file_type = EXT2_FT_DIR;
+ else if (S_ISLNK(mode))
+ de->file_type = EXT2_FT_SYMLINK;
+ else if (S_ISSOCK(mode))
+ de->file_type = EXT2_FT_SOCK;
+ else if (S_ISFIFO(mode))
+ de->file_type = EXT2_FT_FIFO;
+ else if (S_ISCHR(mode))
de->file_type = EXT2_FT_CHRDEV;
else if (S_ISBLK(mode))
de->file_type = EXT2_FT_BLKDEV;
- else if (S_ISFIFO(mode))
- de->file_type = EXT2_FT_FIFO;
- else if (S_ISLNK(mode))
- de->file_type = EXT2_FT_SYMLINK;
- else if (S_ISREG(mode))
- de->file_type = EXT2_FT_REG_FILE;
- else if (S_ISDIR(mode))
- de->file_type = EXT2_FT_DIR;
}
/*
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index cd2762732..196e7aa1b 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -338,7 +338,6 @@ int date_dos2unix(unsigned short time,unsigned short date)
month < 2 ? 1 : 0)+3653);
/* days since 1.1.70 plus 80's leap day */
secs += sys_tz.tz_minuteswest*60;
- if (sys_tz.tz_dsttime) secs -= 3600;
return secs;
}
diff --git a/fs/filesystems.c b/fs/filesystems.c
index bae48e19a..10c8f8bd3 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -138,10 +138,6 @@ void __init filesystem_setup(void)
init_efs_fs();
#endif
-#ifdef CONFIG_AUTOFS_FS
- init_autofs_fs();
-#endif
-
#ifdef CONFIG_ADFS_FS
init_adfs_fs();
#endif
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
index 377b296e8..d1e70e579 100644
--- a/fs/hpfs/hpfs_fn.h
+++ b/fs/hpfs/hpfs_fn.h
@@ -64,13 +64,13 @@ typedef void nonconst; /* What this is for ? */
extern inline time_t local_to_gmt(struct super_block *s, time_t t)
{
extern struct timezone sys_tz;
- return t + sys_tz.tz_minuteswest * 60 - (sys_tz.tz_dsttime ? 3600 : 0) +s->s_hpfs_timeshift;
+ return t + sys_tz.tz_minuteswest * 60 + s->s_hpfs_timeshift;
}
extern inline time_t gmt_to_local(struct super_block *s, time_t t)
{
extern struct timezone sys_tz;
- return t - sys_tz.tz_minuteswest * 60 + (sys_tz.tz_dsttime ? 3600 : 0) -s->s_hpfs_timeshift;
+ return t - sys_tz.tz_minuteswest * 60 - s->s_hpfs_timeshift;
}
/*
diff --git a/fs/inode.c b/fs/inode.c
index d6298d349..4145a2d91 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -398,20 +398,17 @@ void prune_icache(int goal)
int shrink_icache_memory(int priority, int gfp_mask, zone_t *zone)
{
- if (gfp_mask & __GFP_IO)
- {
- int count = 0;
+ int count = 0;
- if (priority)
- count = inodes_stat.nr_unused / priority;
- prune_icache(count);
- /* FIXME: kmem_cache_shrink here should tell us
- the number of pages freed, and it should
- work in a __GFP_DMA/__GFP_HIGHMEM behaviour
- to free only the interesting pages in
- function of the needs of the current allocation. */
- kmem_cache_shrink(inode_cachep);
- }
+ if (priority)
+ count = inodes_stat.nr_unused / priority;
+ prune_icache(count);
+ /* FIXME: kmem_cache_shrink here should tell us
+ the number of pages freed, and it should
+ work in a __GFP_DMA/__GFP_HIGHMEM behaviour
+ to free only the interesting pages in
+ function of the needs of the current allocation. */
+ kmem_cache_shrink(inode_cachep);
return 0;
}
diff --git a/fs/isofs/util.c b/fs/isofs/util.c
index a8962fc76..12cd2d304 100644
--- a/fs/isofs/util.c
+++ b/fs/isofs/util.c
@@ -114,7 +114,6 @@ int iso_date(char * p, int flag)
crtime = 0;
} else {
int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
- extern struct timezone sys_tz;
days = year * 365;
if (year > 2)
@@ -126,8 +125,6 @@ int iso_date(char * p, int flag)
days += day - 1;
crtime = ((((days * 24) + hour) * 60 + minute) * 60)
+ second;
- if (sys_tz.tz_dsttime)
- crtime -= 3600;
/* sign extend */
if (tz & 0x80)
@@ -149,7 +146,7 @@ int iso_date(char * p, int flag)
* NOTE: mkisofs in versions prior to mkisofs-1.10 had
* the sign wrong on the timezone offset. This has now
* been corrected there too, but if you are getting screwy
- * results this may be the explaination. If enough people
+ * results this may be the explanation. If enough people
* complain, a user configuration option could be added
* to add the timezone offset in with the wrong sign
* for 'compatibility' with older discs, but I cannot see how
diff --git a/fs/namei.c b/fs/namei.c
index 97f8232d4..3b0b73686 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1341,7 +1341,7 @@ asmlinkage long sys_rename(const char * oldname, const char * newname)
return error;
}
-int vfs_readlink(struct dentry *dentry, char *buffer, int buflen, char *link)
+int vfs_readlink(struct dentry *dentry, char *buffer, int buflen, const char *link)
{
u32 len;
@@ -1359,7 +1359,7 @@ out:
static inline struct dentry *
__vfs_follow_link(struct dentry *dentry, struct dentry *base,
- unsigned follow, char *link)
+ unsigned follow, const char *link)
{
struct dentry *result;
UPDATE_ATIME(dentry->d_inode);
@@ -1377,7 +1377,7 @@ fail:
struct dentry *
vfs_follow_link(struct dentry *dentry, struct dentry *base,
-unsigned int follow, char *link)
+unsigned int follow, const char *link)
{
return __vfs_follow_link(dentry,base,follow,link);
}
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 31e414ebb..565f88c5b 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -868,6 +868,7 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
struct ncp_server *server = NCP_SERVER(dir);
struct ncp_entry_info finfo;
int error, result, len = dentry->d_name.len + 1;
+ int opmode;
__u8 __name[len];
PPRINTK("ncp_create_new: creating %s/%s, mode=%x\n",
@@ -886,15 +887,22 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
result = ncp_open_create_file_or_subdir(server, dir, __name,
OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
attributes, AR_READ | AR_WRITE, &finfo);
- if (!result) {
- finfo.access = O_RDWR;
- error = ncp_instantiate(dir, dentry, &finfo);
- } else {
- if (result == 0x87) error = -ENAMETOOLONG;
- DPRINTK("ncp_create: %s/%s failed\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
+ opmode = O_RDWR;
+ if (result) {
+ result = ncp_open_create_file_or_subdir(server, dir, __name,
+ OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
+ attributes, AR_WRITE, &finfo);
+ if (result) {
+ if (result == 0x87)
+ error = -ENAMETOOLONG;
+ DPRINTK("ncp_create: %s/%s failed\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+ goto out;
+ }
+ opmode = O_WRONLY;
}
-
+ finfo.access = opmode;
+ error = ncp_instantiate(dir, dentry, &finfo);
out:
return error;
}
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 98fd9f23e..5e28516bf 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -36,9 +36,8 @@ static int ncp_fsync(struct file *file, struct dentry *dentry)
*/
int ncp_make_open(struct inode *inode, int right)
{
- int error, result;
+ int error;
int access;
- struct ncp_entry_info finfo;
error = -EINVAL;
if (!inode) {
@@ -53,6 +52,9 @@ int ncp_make_open(struct inode *inode, int right)
error = -EACCES;
lock_super(inode->i_sb);
if (!NCP_FINFO(inode)->opened) {
+ struct ncp_entry_info finfo;
+ int result;
+
finfo.i.dirEntNum = NCP_FINFO(inode)->dirEntNum;
finfo.i.volNumber = NCP_FINFO(inode)->volNumber;
/* tries max. rights */
@@ -62,10 +64,21 @@ int ncp_make_open(struct inode *inode, int right)
0, AR_READ | AR_WRITE, &finfo);
if (!result)
goto update;
- finfo.access = O_RDONLY;
- result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
+ /* RDWR did not succeeded, try readonly or writeonly as requested */
+ switch (right) {
+ case O_RDONLY:
+ finfo.access = O_RDONLY;
+ result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
NULL, NULL, OC_MODE_OPEN,
0, AR_READ, &finfo);
+ break;
+ case O_WRONLY:
+ finfo.access = O_WRONLY;
+ result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
+ NULL, NULL, OC_MODE_OPEN,
+ 0, AR_WRITE, &finfo);
+ break;
+ }
if (result) {
PPRINTK("ncp_make_open: failed, result=%d\n", result);
goto out_unlock;
@@ -130,7 +143,7 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
error = ncp_make_open(inode, O_RDONLY);
if (error) {
- printk(KERN_ERR "ncp_file_read: open failed, error=%d\n", error);
+ DPRINTK(KERN_ERR "ncp_file_read: open failed, error=%d\n", error);
goto out;
}
@@ -208,9 +221,9 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
errno = 0;
if (!count)
goto out;
- errno = ncp_make_open(inode, O_RDWR);
+ errno = ncp_make_open(inode, O_WRONLY);
if (errno) {
- printk(KERN_ERR "ncp_file_write: open failed, error=%d\n", errno);
+ DPRINTK(KERN_ERR "ncp_file_write: open failed, error=%d\n", errno);
return errno;
}
pos = *ppos;
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index eca5ddf15..84b9e5643 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -683,7 +683,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
DPRINTK("ncpfs: trying to change size to %ld\n",
attr->ia_size);
- if ((result = ncp_make_open(inode, O_RDWR)) < 0) {
+ if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
return -EACCES;
}
ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 6cf94831f..4f7a1d253 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -330,6 +330,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
default:
return -EINVAL;
}
+ /* locking needs both read and write access */
if ((result = ncp_make_open(inode, O_RDWR)) != 0)
{
return result;
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index 806c05d6e..752ae1e1e 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -92,17 +92,9 @@ static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area,
return page;
}
-struct vm_operations_struct ncp_file_mmap =
+static struct vm_operations_struct ncp_file_mmap =
{
- NULL, /* open */
- NULL, /* close */
- NULL, /* unmap */
- NULL, /* protect */
- NULL, /* sync */
- NULL, /* advise */
- ncp_file_mmap_nopage, /* nopage */
- NULL, /* wppage */
- NULL /* swapout */
+ nopage: ncp_file_mmap_nopage,
};
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 9f58b4171..09a16b302 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -416,7 +416,9 @@ wait_on_write_request(struct nfs_wreq *req)
int
nfs_writepage(struct dentry * dentry, struct page *page)
{
- return nfs_writepage_sync(dentry, dentry->d_inode, page, 0, PAGE_SIZE);
+ int result = nfs_writepage_sync(dentry, dentry->d_inode, page, 0, PAGE_SIZE);
+ if ( result == PAGE_SIZE) return 0;
+ return result;
}
/*
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index e0636f635..3b9927c7a 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -494,7 +494,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
error = nfserr_perm;
if (!rqstp->rq_secure && EX_SECURE(exp)) {
printk(KERN_WARNING
- "nfsd: request from insecure port (%08lx:%d)!\n",
+ "nfsd: request from insecure port (%08x:%d)!\n",
ntohl(rqstp->rq_addr.sin_addr.s_addr),
ntohs(rqstp->rq_addr.sin_port));
goto out;
diff --git a/fs/open.c b/fs/open.c
index 82260bd5d..8aa828088 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -306,11 +306,12 @@ asmlinkage long sys_access(const char * filename, int mode)
struct dentry * dentry;
int old_fsuid, old_fsgid;
kernel_cap_t old_cap;
- int res = -EINVAL;
+ int res;
+
+ if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
+ return -EINVAL;
lock_kernel();
- if (mode != (mode & S_IRWXO)) /* where's F_OK, X_OK, W_OK, R_OK? */
- goto out;
old_fsuid = current->fsuid;
old_fsgid = current->fsgid;
old_cap = current->cap_effective;
@@ -337,7 +338,7 @@ asmlinkage long sys_access(const char * filename, int mode)
current->fsuid = old_fsuid;
current->fsgid = old_fsgid;
current->cap_effective = old_cap;
-out:
+
unlock_kernel();
return res;
}
diff --git a/fs/partitions/Config.in b/fs/partitions/Config.in
index 57706a744..6974e1a2d 100644
--- a/fs/partitions/Config.in
+++ b/fs/partitions/Config.in
@@ -21,7 +21,9 @@ if [ "$CONFIG_PARTITION_ADVANCED" = "y" ]; then
bool ' Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
bool ' Unixware slices support' CONFIG_UNIXWARE_DISKLABEL
fi
- bool ' Ultrix partition table support' CONFIG_ULTRIX_PARTITION
+ bool 'SGI partition support' CONFIG_SGI_PARTITION
+ bool 'Ultrix partition table support' CONFIG_ULTRIX_PARTITION
+ bool 'Sun partition tables support' CONFIG_SUN_PARTITION
else
if [ "$ARCH" = "alpha" ]; then
define_bool CONFIG_OSF_PARTITION y
@@ -30,7 +32,8 @@ else
define_bool CONFIG_MAC_PARTITION y
fi
if [ "$CONFIG_AMIGA" != "y" -a "$CONFIG_ATARI" != "y" -a \
- "$CONFIG_MAC" != "y" ]; then
+ "$CONFIG_MAC" != "y" -a "$CONFIG_SGI_IP22" != "y" -a \
+ "$CONFIG_SGI_IP27" != "y" ]; then
define_bool CONFIG_MSDOS_PARTITION y
fi
if [ "$CONFIG_AMIGA" = "y" ]; then
@@ -47,15 +50,13 @@ else
if [ "$CONFIG_ATARI" = "y" ]; then
define_bool CONFIG_ATARI_PARTITION y
fi
- bool 'Ultrix partition table support' CONFIG_ULTRIX_PARTITION
-fi
-if [ "$CONFIG_SGI_IP22" != "y" -a "$CONFIG_SGI_IP27" != "y" ]; then
- bool 'SGI partition support' CONFIG_SGI_PARTITION
-else
- define_bool CONFIG_SGI_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
+ if [ "$CONFIG_SGI_IP22" = "y" -o "$CONFIG_SGI_IP27" = "y" ]; then
+ define_bool CONFIG_SGI_PARTITION y
+ fi
+ if [ "$CONFIG_DECSTATION" = "y" ]; then
+ define_bool CONFIG_ULTRIX_PARTITION y
+ fi
+ if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+ define_bool CONFIG_SUN_PARTITION y
+ fi
fi
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index ec0bd3a4b..d9c4c11de 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -277,7 +277,6 @@ static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor
void register_disk(struct gendisk *gdev, kdev_t dev, unsigned minors,
struct block_device_operations *ops, long size)
{
- unsigned first = (unsigned)dev;
if (!gdev)
return;
grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size);
diff --git a/fs/partitions/sgi.c b/fs/partitions/sgi.c
index 8ae97eca0..db9c1ae39 100644
--- a/fs/partitions/sgi.c
+++ b/fs/partitions/sgi.c
@@ -44,15 +44,15 @@ int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, in
struct sgi_partition *p;
if(!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) {
- printk("Dev %s: unable to read partition table\n", kdevname(dev));
+ printk(KERN_WARNING "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);
+ /*printk("Dev %s SGI disklabel: bad magic %08x\n",
+ kdevname(dev), magic);*/
brelse(bh);
return 0;
}
@@ -62,7 +62,7 @@ int sgi_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, in
csum += be32_to_cpu(cs);
}
if(csum) {
- printk("Dev %s SGI disklabel: csum bad, label corrupted\n",
+ printk(KERN_WARNING "Dev %s SGI disklabel: csum bad, label corrupted\n",
kdevname(dev));
brelse(bh);
return 0;
diff --git a/fs/partitions/sun.c b/fs/partitions/sun.c
index 5d82a70c6..5f31cde4b 100644
--- a/fs/partitions/sun.c
+++ b/fs/partitions/sun.c
@@ -48,15 +48,15 @@ int sun_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, in
unsigned long spc;
if(!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) {
- printk("Dev %s: unable to read partition table\n",
+ printk(KERN_WARNING "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));
+/* printk(KERN_INFO "Dev %s Sun disklabel: bad magic %04x\n",
+ kdevname(dev), be16_to_cpu(label->magic)); */
brelse(bh);
return 0;
}
diff --git a/fs/partitions/ultrix.c b/fs/partitions/ultrix.c
index 1de4d04b0..654a4fbd1 100644
--- a/fs/partitions/ultrix.c
+++ b/fs/partitions/ultrix.c
@@ -13,11 +13,11 @@
#include <linux/blk.h>
#include "check.h"
-#include "ultrix.h"
-int ultrix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int first_part_minor)
+static int ultrix_partition(struct gendisk *hd, kdev_t dev,
+ unsigned long first_sector, int curren_minor)
{
- int i;
+ int i, minor = current_minor;
struct buffer_head *bh;
struct ultrix_disklabel {
s32 pt_magic; /* magic no. indicating part. info exits */
@@ -28,6 +28,12 @@ int ultrix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
} 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);
@@ -38,14 +44,12 @@ int ultrix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
+ get_ptable_blocksize(dev)
- sizeof(struct ultrix_disklabel));
- if (le32_to_cpu(label->pt_magic) == PT_MAGIC &&
- le32_to_cpu(label->pt_valid == PT_VALID)) {
- for (i=0; i<8; i++, first_part_minor++)
- if (le32_to_cpu(label->pt_part[i].pi_nblocks))
- add_gd_partition(hd, first_part_minor,
- le32_to_cpu(label->pt_part[i].pi_blkoff),
- le32_to_cpu(label->pt_part[i].pi_nblocks));
-
+ 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;
@@ -54,4 +58,3 @@ int ultrix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
return 0;
}
}
-
diff --git a/fs/partitions/ultrix.h b/fs/partitions/ultrix.h
index b2d24fdfd..385a32590 100644
--- a/fs/partitions/ultrix.h
+++ b/fs/partitions/ultrix.h
@@ -2,12 +2,8 @@
* fs/partitions/ultrix.h
*/
-#define PT_MAGIC 0x032957 /* Partition magic number */
-#define PT_VALID 1 /* Indicates if struct is valid */
+static int ultrix_partition(struct gendisk *hd, kdev_t dev,
+ unsigned long first_sector);
-#define SBLOCK ((unsigned long)((16384 - sizeof(struct ultrix_disklabel)) \
- /get_ptable_blocksize(dev)))
-
-int ultrix_partition(struct gendisk *hd, kdev_t dev,
- unsigned long first_sector, int first_part_minor);
+#define SGI_LABEL_MAGIC 0x0be5a941
diff --git a/fs/select.c b/fs/select.c
index 674cfdaa2..b664d3e81 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -8,6 +8,10 @@
* COFF/ELF binary emulation. If the process has the STICKY_TIMEOUTS
* flag set in its personality we do *not* modify the given timeout
* parameter to reflect time remaining.
+ *
+ * 24 January 2000
+ * Changed sys_poll()/do_poll() to use PAGE_SIZE chunk-based allocation
+ * of fds to overcome nfds < 16390 descriptors limit (Tigran Aivazian).
*/
#include <linux/malloc.h>
@@ -328,39 +332,48 @@ out_nofds:
return ret;
}
-static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait,
- long timeout)
+#define POLLFD_PER_PAGE ((PAGE_SIZE) / sizeof(struct pollfd))
+
+static void do_pollfd(struct pollfd * fdp, poll_table * wait, int *count)
+{
+ int fd;
+ unsigned int mask;
+
+ mask = 0;
+ fd = fdp->fd;
+ if (fd >= 0) {
+ struct file * file = fget(fd);
+ mask = POLLNVAL;
+ if (file != NULL) {
+ mask = DEFAULT_POLLMASK;
+ if (file->f_op && file->f_op->poll)
+ mask = file->f_op->poll(file, wait);
+ mask &= fdp->events | POLLERR | POLLHUP;
+ fput(file);
+ }
+ if (mask) {
+ wait = NULL;
+ (*count)++;
+ }
+ }
+ fdp->revents = mask;
+}
+
+static int do_poll(unsigned int nfds, unsigned int nchunks, unsigned int nleft,
+ struct pollfd *fds[], poll_table *wait, long timeout)
{
int count = 0;
for (;;) {
- unsigned int j;
- struct pollfd * fdpnt;
+ unsigned int i, j;
set_current_state(TASK_INTERRUPTIBLE);
- for (fdpnt = fds, j = 0; j < nfds; j++, fdpnt++) {
- int fd;
- unsigned int mask;
-
- mask = 0;
- fd = fdpnt->fd;
- if (fd >= 0) {
- struct file * file = fget(fd);
- mask = POLLNVAL;
- if (file != NULL) {
- mask = DEFAULT_POLLMASK;
- if (file->f_op && file->f_op->poll)
- mask = file->f_op->poll(file, wait);
- mask &= fdpnt->events | POLLERR | POLLHUP;
- fput(file);
- }
- if (mask) {
- wait = NULL;
- count++;
- }
- }
- fdpnt->revents = mask;
- }
+ for (i=0; i < nchunks; i++)
+ for (j = 0; j < POLLFD_PER_PAGE; j++)
+ do_pollfd(fds[i] + j, wait, &count);
+ if (nleft)
+ for (j = 0; j < nleft; j++)
+ do_pollfd(fds[nchunks] + j, wait, &count);
wait = NULL;
if (count || !timeout || signal_pending(current))
@@ -373,18 +386,17 @@ static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait,
asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
{
- int i, fdcount, err, size;
- struct pollfd * fds, *fds1;
+ int i, j, fdcount, err;
+ struct pollfd **fds;
poll_table *wait_table = NULL, *wait = NULL;
+ int nchunks, nleft;
- lock_kernel();
/* Do a sanity check on nfds ... */
- err = -EINVAL;
if (nfds > current->files->max_fds)
- goto out;
+ return -EINVAL;
if (timeout) {
- /* Carefula about overflow in the intermediate values */
+ /* Careful about overflow in the intermediate values */
if ((unsigned long) timeout < MAX_SCHEDULE_TIMEOUT / HZ)
timeout = (unsigned long)(timeout*HZ+999)/1000+1;
else /* Negative or overflow */
@@ -402,32 +414,62 @@ asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
wait = wait_table;
}
- size = nfds * sizeof(struct pollfd);
- fds = (struct pollfd *) kmalloc(size, GFP_KERNEL);
- if (!fds)
+ fds = (struct pollfd **)kmalloc(
+ (1 + (nfds - 1) / POLLFD_PER_PAGE) * sizeof(struct pollfd *),
+ GFP_KERNEL);
+ if (fds == NULL)
goto out;
+ nchunks = 0;
+ nleft = nfds;
+ while (nleft > POLLFD_PER_PAGE) { /* allocate complete PAGE_SIZE chunks */
+ fds[nchunks] = (struct pollfd *)__get_free_page(GFP_KERNEL);
+ if (fds[nchunks] == NULL)
+ goto out_fds;
+ nchunks++;
+ nleft -= POLLFD_PER_PAGE;
+ }
+ if (nleft) { /* allocate last PAGE_SIZE chunk, only nleft elements used */
+ fds[nchunks] = (struct pollfd *)__get_free_page(GFP_KERNEL);
+ if (fds[nchunks] == NULL)
+ goto out_fds;
+ }
+
err = -EFAULT;
- if (copy_from_user(fds, ufds, size))
- goto out_fds;
+ for (i=0; i < nchunks; i++)
+ if (copy_from_user(fds[i], ufds + i*POLLFD_PER_PAGE, PAGE_SIZE))
+ goto out_fds1;
+ if (nleft) {
+ if (copy_from_user(fds[nchunks], ufds + nchunks*POLLFD_PER_PAGE,
+ nleft * sizeof(struct pollfd)))
+ goto out_fds1;
+ }
- fdcount = do_poll(nfds, fds, wait, timeout);
+ lock_kernel();
+ fdcount = do_poll(nfds, nchunks, nleft, fds, wait, timeout);
+ unlock_kernel();
/* OK, now copy the revents fields back to user space. */
- fds1 = fds;
- for(i=0; i < (int)nfds; i++, ufds++, fds1++) {
- __put_user(fds1->revents, &ufds->revents);
- }
+ for(i=0; i < nchunks; i++)
+ for (j=0; j < POLLFD_PER_PAGE; j++, ufds++)
+ __put_user((fds[i] + j)->revents, &ufds->revents);
+ if (nleft)
+ for (j=0; j < nleft; j++, ufds++)
+ __put_user((fds[nchunks] + j)->revents, &ufds->revents);
err = fdcount;
if (!fdcount && signal_pending(current))
err = -EINTR;
+out_fds1:
+ if (nleft)
+ free_page((unsigned long)(fds[nchunks]));
out_fds:
+ for (i=0; i < nchunks; i++)
+ free_page((unsigned long)(fds[i]));
kfree(fds);
out:
if (wait)
free_wait(wait_table);
- unlock_kernel();
return err;
}
diff --git a/fs/super.c b/fs/super.c
index 889938116..71b38fd46 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -302,16 +302,22 @@ static struct proc_nfs_info {
int get_filesystem_info( char *buf )
{
- struct vfsmount *tmp = vfsmntlist;
+ struct vfsmount *tmp;
struct proc_fs_info *fs_infop;
struct proc_nfs_info *nfs_infop;
struct nfs_server *nfss;
int len = 0;
+ char *path,*buffer = (char *) __get_free_page(GFP_KERNEL);
- while ( tmp && len < PAGE_SIZE - 160)
- {
+ if (!buffer) return 0;
+ for (tmp = vfsmntlist; tmp && len < PAGE_SIZE - 160;
+ tmp = tmp->mnt_next) {
+ path = d_path(tmp->mnt_sb->s_root, buffer, PAGE_SIZE);
+ if (!path)
+ continue;
len += sprintf( buf + len, "%s %s %s %s",
- tmp->mnt_devname, tmp->mnt_dirname, tmp->mnt_sb->s_type->name,
+ tmp->mnt_devname, path,
+ tmp->mnt_sb->s_type->name,
tmp->mnt_flags & MS_RDONLY ? "ro" : "rw" );
for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
if (tmp->mnt_flags & fs_infop->flag) {
@@ -365,9 +371,9 @@ int get_filesystem_info( char *buf )
nfss->hostname);
}
len += sprintf( buf + len, " 0 0\n" );
- tmp = tmp->mnt_next;
}
+ free_page((unsigned long) buffer);
return len;
}
@@ -681,7 +687,7 @@ static struct block_device *do_umount(kdev_t dev, int unmount_root, int flags)
shrink_dcache_sb(sb);
fsync_dev(dev);
- if (dev==ROOT_DEV && !unmount_root) {
+ if (sb == current->fs->root->d_sb && !unmount_root) {
/*
* Special case for "unmounting" root ...
* we just try to remount it readonly.
@@ -1214,6 +1220,113 @@ void __init mount_root(void)
}
+static void chroot_fs_refs(struct dentry *old_root,
+ struct dentry *new_root)
+{
+ struct task_struct *p;
+
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if (!p->fs) continue;
+ if (p->fs->root == old_root) {
+ dput(old_root);
+ p->fs->root = dget(new_root);
+ printk(KERN_DEBUG "chroot_fs_refs: changed root of "
+ "process %d\n",p->pid);
+ }
+ if (p->fs->pwd == old_root) {
+ dput(old_root);
+ p->fs->pwd = dget(new_root);
+ printk(KERN_DEBUG "chroot_fs_refs: changed cwd of "
+ "process %d\n",p->pid);
+ }
+ }
+ read_unlock(&tasklist_lock);
+}
+
+
+/*
+ * Moves the current root to put_root, and sets root/cwd of all processes
+ * which had them on the old root to new_root.
+ *
+ * Note:
+ * - we don't move root/cwd if they are not at the root (reason: if something
+ * cared enough to change them, it's probably wrong to force them elsewhere)
+ * - it's okay to pick a root that isn't the root of a file system, e.g.
+ * /nfs/my_root where /nfs is the mount point. Better avoid creating
+ * unreachable mount points this way, though.
+ */
+
+asmlinkage long sys_pivot_root(const char *new_root, const char *put_old)
+{
+ struct dentry *root = current->fs->root;
+ struct dentry *d_new_root, *d_put_old, *covered;
+ struct dentry *root_dev_root, *new_root_dev_root;
+ struct dentry *walk, *next;
+ int error;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ lock_kernel();
+ d_new_root = namei(new_root);
+ if (IS_ERR(d_new_root)) {
+ error = PTR_ERR(d_new_root);
+ goto out0;
+ }
+ d_put_old = namei(put_old);
+ if (IS_ERR(d_put_old)) {
+ error = PTR_ERR(d_put_old);
+ goto out1;
+ }
+ down(&mount_sem);
+ if (!d_new_root->d_inode || !d_put_old->d_inode) {
+ error = -ENOENT;
+ goto out2;
+ }
+ if (!S_ISDIR(d_new_root->d_inode->i_mode) ||
+ !S_ISDIR(d_put_old->d_inode->i_mode)) {
+ error = -ENOTDIR;
+ goto out2;
+ }
+ error = -EBUSY;
+ if (d_new_root->d_sb == root->d_sb || d_put_old->d_sb == root->d_sb)
+ goto out2; /* loop */
+ if (d_put_old != d_put_old->d_covers)
+ goto out2; /* mount point is busy */
+ error = -EINVAL;
+ walk = d_put_old; /* make sure we can reach put_old from new_root */
+ for (;;) {
+ next = walk->d_covers->d_parent;
+ if (next == walk)
+ goto out2;
+ if (next == d_new_root)
+ break;
+ walk = next;
+ }
+
+ new_root_dev_root = d_new_root->d_sb->s_root;
+ covered = new_root_dev_root->d_covers;
+ new_root_dev_root->d_covers = new_root_dev_root;
+ dput(covered);
+ covered->d_mounts = covered;
+
+ root_dev_root = root->d_sb->s_root;
+ root_dev_root->d_covers = dget(d_put_old);
+ d_put_old->d_mounts = root_dev_root;
+ chroot_fs_refs(root,d_new_root);
+ error = 0;
+out2:
+ up(&mount_sem);
+ dput(d_put_old);
+out1:
+ dput(d_new_root);
+out0:
+ unlock_kernel();
+ return error;
+}
+
+
#ifdef CONFIG_BLK_DEV_INITRD
int __init change_root(kdev_t new_root_dev,const char *put_old)
@@ -1272,7 +1385,7 @@ int __init change_root(kdev_t new_root_dev,const char *put_old)
}
return 0;
}
- printk(KERN_ERR "error %d\n",PTR_ERR(bdev));
+ printk(KERN_ERR "error %ld\n",PTR_ERR(bdev));
return error;
}
remove_vfsmnt(old_root_dev);
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index 7b7d065ff..916683186 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -67,13 +67,13 @@ static struct file_operations udf_dir_operations = {
struct inode_operations udf_dir_inode_operations = {
&udf_dir_operations,
-#ifdef CONFIG_UDF_RW
+#if CONFIG_UDF_RW == 1
udf_create, /* create */
#else
NULL, /* create */
#endif
udf_lookup, /* lookup */
-#ifdef CONFIG_UDF_RW
+#if CONFIG_UDF_RW == 1
udf_link, /* link */
udf_unlink, /* unlink */
udf_symlink, /* symlink */
@@ -139,7 +139,7 @@ int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
if ( filp->f_pos == 0 )
{
- if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino) < 0)
+ if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino))
return 0;
}
@@ -161,7 +161,7 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
char *nameptr;
Uint16 liu;
Uint8 lfi;
- loff_t size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2;
+ loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
struct buffer_head * bh = NULL;
lb_addr bloc, eloc;
Uint32 extoffset, elen, offset;
@@ -170,7 +170,7 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
return 1;
if (nf_pos == 0)
- nf_pos = (UDF_I_EXT0OFFS(dir) >> 2);
+ nf_pos = (udf_ext0_offset(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),
@@ -251,7 +251,7 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
if (!lfi) /* parent directory */
{
- if (filldir(dirent, "..", 2, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino) < 0)
+ if (filldir(dirent, "..", 2, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino))
{
if (fibh.sbh != fibh.ebh)
udf_release_data(fibh.ebh);
@@ -264,7 +264,7 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
{
if ((flen = udf_get_filename(nameptr, fname, lfi)))
{
- if (filldir(dirent, fname, flen, filp->f_pos, iblock) < 0)
+ if (filldir(dirent, fname, flen, filp->f_pos, iblock))
{
if (fibh.sbh != fibh.ebh)
udf_release_data(fibh.ebh);
diff --git a/fs/udf/directory.c b/fs/udf/directory.c
index b8a94e8f5..84c97ee9d 100644
--- a/fs/udf/directory.c
+++ b/fs/udf/directory.c
@@ -213,8 +213,8 @@ udf_get_fileident(void * buffer, int bufsize, int * offset)
#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);
+ udf_debug("offset: %u sizeof: %lu bufsize: %u\n",
+ *offset, (unsigned long)sizeof(struct FileIdentDesc), bufsize);
#endif
return NULL;
}
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 81cddaa3f..8ea44d2a8 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -43,94 +43,6 @@
#include "udf_i.h"
#include "udf_sb.h"
-static loff_t udf_file_llseek(struct file *, loff_t, 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 *);
-static int udf_open_file(struct inode *, struct file *);
-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 */
- udf_open_file, /* open */
- NULL, /* flush */
- udf_release_file, /* release */
- udf_sync_file, /* fsync */
- NULL, /* fasync */
- 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 */
-#ifdef CONFIG_UDF_RW
- udf_truncate, /* truncate */
-#else
- NULL, /* truncate */
-#endif
- NULL, /* permission */
- 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 /* 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 */
-#ifdef CONFIG_UDF_RW
- udf_truncate, /* truncate */
-#else
- NULL, /* truncate */
-#endif
- NULL, /* permission */
- NULL /* revalidate */
-};
-
/*
* Make sure the offset never goes beyond the 32-bit mark..
*/
@@ -181,104 +93,93 @@ static ssize_t udf_file_write(struct file * file, const char * buf,
{
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);
- else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
- return err;
- }
retval = generic_file_write(file, buf, count, ppos, block_write_partial_page);
if (retval > 0)
{
+ remove_suid(inode);
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
UDF_I_UCTIME(inode) = UDF_I_UMTIME(inode) = CURRENT_UTIME;
+ mark_inode_dirty(inode);
}
- 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)
+int udf_write_partial_page_adinicb(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
{
- struct inode *inode = filp->f_dentry->d_inode;
- loff_t size, left, pos;
- Uint32 block;
- struct buffer_head *bh = NULL;
+ struct inode *inode = file->f_dentry->d_inode;
+ int err = 0, block;
+ struct buffer_head *bh;
+ unsigned long kaddr = 0;
+
+ if (!PageLocked(page))
+ BUG();
+ if (offset < 0 || offset >= (inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode)))
+ BUG();
+ if (bytes+offset < 0 || bytes+offset > (inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode)))
+ BUG();
+
+ kaddr = kmap(page);
+ block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
+ bh = getblk (inode->i_dev, block, inode->i_sb->s_blocksize);
+ if (!buffer_uptodate(bh))
+ {
+ ll_rw_block (READ, 1, &bh);
+ wait_on_buffer(bh);
+ }
+ err = copy_from_user((char *)kaddr + offset, buf, bytes);
+ memcpy(bh->b_data + udf_file_entry_alloc_offset(inode) + offset,
+ (char *)kaddr + offset, bytes);
+ mark_buffer_dirty(bh, 0);
+ brelse(bh);
+ kunmap(page);
+ SetPageUptodate(page);
+ return bytes;
+}
+
+static ssize_t udf_file_write_adinicb(struct file * file, const char * buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t retval;
+ struct inode *inode = file->f_dentry->d_inode;
+ int err, pos;
- size = inode->i_size;
- if (*loff > size)
- left = 0;
+ if (file->f_flags & O_APPEND)
+ pos = inode->i_size;
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)))
+ pos = *ppos;
+
+ if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
+ pos + count))
{
- return 0;
+ udf_expand_file_adinicb(file, pos + count, &err);
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+ {
+ udf_debug("udf_expand_adinicb: err=%d\n", err);
+ return err;
+ }
+ else
+ return udf_file_write(file, buf, count, ppos);
}
- if (!copy_to_user(buf, bh->b_data + pos, left))
- *loff += left;
else
- left = -EFAULT;
+ {
+ if (pos + count > inode->i_size)
+ UDF_I_LENALLOC(inode) = pos + count;
+ else
+ UDF_I_LENALLOC(inode) = inode->i_size;
+ }
- udf_release_data(bh);
+ retval = generic_file_write(file, buf, count, ppos, udf_write_partial_page_adinicb);
- return left;
+ if (retval > 0)
+ {
+ remove_suid(inode);
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ UDF_I_UCTIME(inode) = UDF_I_UMTIME(inode) = CURRENT_UTIME;
+ mark_inode_dirty(inode);
+ }
+ return retval;
}
/*
@@ -435,3 +336,85 @@ static int udf_open_file(struct inode * inode, struct file * filp)
return -EFBIG;
return 0;
}
+
+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 */
+ udf_open_file, /* open */
+ NULL, /* flush */
+ udf_release_file, /* release */
+ udf_sync_file, /* fsync */
+ NULL, /* fasync */
+ 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 */
+#if CONFIG_UDF_RW == 1
+ udf_truncate, /* truncate */
+#else
+ NULL, /* truncate */
+#endif
+ NULL, /* permission */
+ NULL /* revalidate */
+};
+
+static struct file_operations udf_file_operations_adinicb = {
+ udf_file_llseek, /* llseek */
+ generic_file_read, /* read */
+ udf_file_write_adinicb, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ udf_ioctl, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* open */
+ NULL, /* flush */
+ udf_release_file, /* release */
+ udf_sync_file_adinicb, /* fsync */
+ NULL, /* fasync */
+ 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 */
+ udf_readpage_adinicb, /* readpage */
+ udf_writepage_adinicb, /* writepage */
+#if CONFIG_UDF_RW == 1
+ udf_truncate_adinicb, /* truncate */
+#else
+ NULL, /* truncate */
+#endif
+ NULL, /* permission */
+ NULL /* revalidate */
+};
diff --git a/fs/udf/fsync.c b/fs/udf/fsync.c
index 3e2b95c19..b5c10c91b 100644
--- a/fs/udf/fsync.c
+++ b/fs/udf/fsync.c
@@ -15,18 +15,18 @@
* 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
+ * (C) 1999-2000 Ben Fennema
+ * (C) 1999-2000 Stelias Computing Inc
*
* HISTORY
*
* 05/22/99 blf Created.
- *
*/
#include "udfdecl.h"
#include <linux/fs.h>
+#include <linux/locks.h>
#include <linux/udf_fs.h>
#include "udf_i.h"
@@ -40,10 +40,21 @@ static int sync_extent_block (struct inode * inode, Uint32 block, int wait)
if (!bh)
return 0;
if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
- brelse (bh);
- return -1;
+ /* There can be a parallell read(2) that started read-I/O
+ on the buffer so we can't assume that there's been
+ an I/O error without first waiting I/O completation. */
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh))
+ {
+ brelse (bh);
+ return -1;
+ }
}
if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
+ if (wait)
+ /* when we return from fsync all the blocks
+ must be _just_ stored on disk */
+ wait_on_buffer(bh);
brelse (bh);
return 0;
}
@@ -89,8 +100,7 @@ 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)
+ if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
{
/*
* Don't sync fast links! or ICB_FLAG_AD_IN_ICB
@@ -108,3 +118,8 @@ skip:
err |= udf_sync_inode (inode);
return err ? -EIO : 0;
}
+
+int udf_sync_file_adinicb(struct file * file, struct dentry *dentry)
+{
+ return udf_sync_inode(dentry->d_inode) ? -EIO : 0;
+}
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index 32f60fef5..8badac9d9 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -15,7 +15,7 @@
* ftp://prep.ai.mit.edu/pub/gnu/GPL
* Each contributing author retains all rights to their own work.
*
- * (C) 1998-1999 Ben Fennema
+ * (C) 1998-2000 Ben Fennema
*
* HISTORY
*
@@ -148,16 +148,7 @@ struct inode * udf_new_inode (const struct inode *dir, int mode, int * err)
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;
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index e2e12df8e..2ea1f980b 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -16,8 +16,8 @@
* Each contributing author retains all rights to their own work.
*
* (C) 1998 Dave Boynton
- * (C) 1998-1999 Ben Fennema
- * (C) 1999 Stelias Computing Inc
+ * (C) 1998-2000 Ben Fennema
+ * (C) 1999-2000 Stelias Computing Inc
*
* HISTORY
*
@@ -31,7 +31,6 @@
* 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"
@@ -58,8 +57,6 @@ 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
*
@@ -99,56 +96,14 @@ void udf_delete_inode(struct inode * inode)
{
inode->i_size = 0;
if (inode->i_blocks)
- udf_truncate(inode);
+ inode->i_op->truncate(inode);
udf_free_inode(inode);
}
void udf_discard_prealloc(struct inode * inode)
{
-#ifdef UDF_PREALLOCATE
- lb_addr bloc, eloc;
- Uint32 extoffset, elen, nelen, offset, adsize = 0;
- struct buffer_head *bh = NULL;
-
- if ((inode->i_size > 0) &&
- (inode_bmap(inode, (inode->i_size-1) >> inode->i_sb->s_blocksize_bits,
- &bloc, &extoffset, &eloc, &elen, &offset, &bh) ==
- EXTENT_RECORDED_ALLOCATED))
- {
- 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
- {
- udf_release_data(bh);
- return;
- }
-
- nelen = (EXTENT_RECORDED_ALLOCATED << 30) |
- ((((elen - 1) & ~(inode->i_sb->s_blocksize - 1)) |
- ((inode->i_size - 1) & (inode->i_sb->s_blocksize - 1))) + 1);
-
- if (nelen != ((EXTENT_RECORDED_ALLOCATED << 30) | elen))
- {
- extoffset -= adsize;
- udf_write_aext(inode, bloc, &extoffset, eloc, nelen, &bh, 1);
- }
-
- if (udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 0) ==
- EXTENT_NOT_RECORDED_ALLOCATED)
- {
- udf_free_blocks(inode, eloc, 0, elen >> inode->i_sb->s_blocksize_bits);
- memset(&eloc, 0x00, sizeof(lb_addr));
- udf_write_aext(inode, bloc, &extoffset, eloc, 0, &bh, 1);
- UDF_I_LENALLOC(inode) -= adsize;
- udf_write_inode(inode);
- }
- udf_release_data(bh);
- }
- else if (bh)
- udf_release_data(bh);
-#endif
+ if (inode->i_size && UDF_I_ALLOCTYPE(inode) != ICB_FLAG_AD_IN_ICB)
+ udf_trunc(inode);
}
static int udf_alloc_block(struct inode *inode, Uint16 partition,
@@ -162,108 +117,138 @@ static int udf_alloc_block(struct inode *inode, Uint16 partition,
return result;
}
-struct buffer_head * udf_expand_adinicb(struct inode *inode, int *block, int isdir, int *err)
+void udf_expand_file_adinicb(struct file * filp, int newsize, int * err)
{
- if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
- {
- long_ad newad;
- int newblock;
- struct buffer_head *sbh = NULL, *dbh = NULL;
+ struct inode * inode = filp->f_dentry->d_inode;
+ struct buffer_head *bh = NULL;
+ struct page *page;
+ unsigned long kaddr = 0;
- if (!UDF_I_LENALLOC(inode))
- {
- UDF_I_EXT0OFFS(inode) = 0;
- UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG;
- mark_inode_dirty(inode);
- if (inode->i_op == &udf_file_inode_operations_adinicb)
- inode->i_op = &udf_file_inode_operations;
- return NULL;
- }
+ if (!UDF_I_LENALLOC(inode))
+ {
+ UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG;
+ mark_inode_dirty(inode);
+ inode->i_op = &udf_file_inode_operations;
+ filp->f_op = inode->i_op->default_file_ops;
+ return;
+ }
- /* alloc block, and copy data to it */
- *block = udf_alloc_block(inode,
- UDF_I_LOCATION(inode).partitionReferenceNum,
- UDF_I_LOCATION(inode).logicalBlockNum, err);
+ bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+ if (!bh)
+ return;
+ page = grab_cache_page(&inode->i_data, 0);
+ if (!PageLocked(page))
+ BUG();
+ if (!Page_Uptodate(page))
+ {
+ kaddr = kmap(page);
+ memset((char *)kaddr + UDF_I_LENALLOC(inode), 0x00,
+ PAGE_CACHE_SIZE - UDF_I_LENALLOC(inode));
+ memcpy((char *)kaddr, bh->b_data + udf_file_entry_alloc_offset(inode),
+ UDF_I_LENALLOC(inode));
+ kunmap(page);
+ }
+ memset(bh->b_data + udf_file_entry_alloc_offset(inode),
+ 0, UDF_I_LENALLOC(inode));
+ UDF_I_LENALLOC(inode) = 0;
+ UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG;
+ inode->i_blocks = inode->i_sb->s_blocksize / 512;
+ mark_buffer_dirty(bh, 1);
+ udf_release_data(bh);
- 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;
- loff_t f_pos = UDF_I_EXT0OFFS(inode) >> 2;
- loff_t 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);
+ block_write_full_page(filp->f_dentry, page);
+ UnlockPage(page);
+ page_cache_release(page);
- memset(sbh->b_data + udf_file_entry_alloc_offset(inode),
- 0, UDF_I_LENALLOC(inode));
+ mark_inode_dirty(inode);
+ inode->i_version ++;
+ inode->i_op = &udf_file_inode_operations;
+ filp->f_op = inode->i_op->default_file_ops;
+}
- memset(&newad, 0x00, sizeof(long_ad));
- 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 */
+struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int *err)
+{
+ long_ad newad;
+ int newblock;
+ struct buffer_head *sbh = NULL, *dbh = NULL;
- memcpy(sbh->b_data + udf_file_entry_alloc_offset(inode),
- &newad, sizeof(newad));
+ struct udf_fileident_bh sfibh, dfibh;
+ loff_t f_pos = udf_ext0_offset(inode) >> 2;
+ int size = (udf_ext0_offset(inode) + inode->i_size) >> 2;
+ struct FileIdentDesc cfi, *sfi, *dfi;
- UDF_I_LENALLOC(inode) = sizeof(newad);
- UDF_I_EXT0OFFS(inode) = 0;
+ if (!inode->i_size)
+ {
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;
+ return NULL;
}
- else
+
+ /* 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;
+
+ 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;
+ }
+ }
+ mark_buffer_dirty(dbh, 1);
+
+ memset(sbh->b_data + udf_file_entry_alloc_offset(inode),
+ 0, UDF_I_LENALLOC(inode));
+
+ memset(&newad, 0x00, sizeof(long_ad));
+ newad.extLength = inode->i_size;
+ newad.extLocation.logicalBlockNum = *block;
+ newad.extLocation.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
+ /* UniqueID stuff */
+
+ memcpy(sbh->b_data + udf_file_entry_alloc_offset(inode),
+ &newad, sizeof(newad));
+
+ UDF_I_LENALLOC(inode) = sizeof(newad);
+ UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG;
+ inode->i_blocks = inode->i_sb->s_blocksize / 512;
+ mark_buffer_dirty(sbh, 1);
+ udf_release_data(sbh);
+ mark_inode_dirty(inode);
+ inode->i_version ++;
+ return dbh;
}
struct buffer_head * udf_getblk(struct inode * inode, long block,
@@ -282,6 +267,8 @@ struct buffer_head * udf_getblk(struct inode * inode, long block,
bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
if (buffer_new(&dummy))
{
+ if (!buffer_uptodate(bh))
+ wait_on_buffer(bh);
memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
mark_buffer_uptodate(bh, 1);
mark_buffer_dirty(bh, 1);
@@ -310,6 +297,8 @@ int udf_get_block(struct inode *inode, long block, struct buffer_head *bh_result
}
err = -EIO;
+ new = 0;
+ bh = NULL;
lock_kernel();
@@ -479,7 +468,7 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
}
/* if the current extent is not recorded but allocated, get the
- block in the extent corresponding to the requested block */
+ 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 */
@@ -522,12 +511,6 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
udf_release_data(pbh);
- if (pextoffset == udf_file_entry_alloc_offset(inode))
- {
- 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)))
{
@@ -541,11 +524,9 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
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))
+ if (IS_SYNC(inode))
udf_sync_inode(inode);
else
-#endif
mark_inode_dirty(inode);
return result;
}
@@ -830,9 +811,16 @@ struct buffer_head * udf_bread(struct inode * inode, int block,
*
* 12/19/98 dgb Updated to fix size problems.
*/
+
void
udf_read_inode(struct inode *inode)
{
+ memset(&UDF_I_LOCATION(inode), 0xFF, sizeof(lb_addr));
+}
+
+void
+__udf_read_inode(struct inode *inode)
+{
struct buffer_head *bh = NULL;
struct FileEntry *fe;
Uint16 ident;
@@ -851,17 +839,9 @@ udf_read_inode(struct inode *inode)
* i_op = NULL;
*/
- inode->i_blksize = inode->i_sb->s_blocksize;
+ inode->i_blksize = PAGE_SIZE;
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)
@@ -904,11 +884,11 @@ udf_read_inode(struct inode *inode)
if (ident == TID_FILE_ENTRY ||
ident == TID_EXTENDED_FILE_ENTRY)
{
- memcpy(&UDF_SB_LOCATION(inode->i_sb), &loc, sizeof(lb_addr));
+ memcpy(&UDF_I_LOCATION(inode), &loc, sizeof(lb_addr));
udf_release_data(bh);
udf_release_data(ibh);
udf_release_data(nbh);
- udf_read_inode(inode);
+ __udf_read_inode(inode);
return;
}
else
@@ -957,11 +937,11 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
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_uid = le32_to_cpu(fe->uid);
+ if ( inode->i_uid == -1 ) 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_gid = le32_to_cpu(fe->gid);
+ if ( inode->i_gid == -1 ) inode->i_gid = UDF_SB(inode->i_sb)->s_gid;
inode->i_nlink = le16_to_cpu(fe->fileLinkCount);
if (!inode->i_nlink)
@@ -976,12 +956,6 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
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;
@@ -1074,58 +1048,6 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
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:
@@ -1162,7 +1084,6 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
}
case FILE_TYPE_SYMLINK:
{
- /* untested! */
inode->i_op = &udf_symlink_inode_operations;
inode->i_mode = S_IFLNK|S_IRWXUGO;
break;
@@ -1184,7 +1105,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
if (dsea)
{
- init_special_inode(inode, inode->i_mode,
+ init_special_inode(inode, inode->i_mode,
((le32_to_cpu(dsea->majorDeviceIdent)) << 8) |
(le32_to_cpu(dsea->minorDeviceIdent) & 0xFF));
/* Developer ID ??? */
@@ -1440,19 +1361,11 @@ udf_iget(struct super_block *sb, lb_addr ino)
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");
@@ -1463,6 +1376,12 @@ udf_iget(struct super_block *sb, lb_addr ino)
iput(inode);
return NULL;
}
+ else if (UDF_I_LOCATION(inode).logicalBlockNum == 0xFFFFFFFF &&
+ UDF_I_LOCATION(inode).partitionReferenceNum == 0xFFFF)
+ {
+ memcpy(&UDF_I_LOCATION(inode), &ino, sizeof(lb_addr));
+ __udf_read_inode(inode);
+ }
if ( ino.logicalBlockNum >= UDF_SB_PARTLEN(sb, ino.partitionReferenceNum) )
{
@@ -1732,6 +1651,14 @@ int udf_next_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
}
break;
}
+ case ICB_FLAG_AD_IN_ICB:
+ {
+ *bloc = *eloc = UDF_I_LOCATION(inode);
+ *elen = UDF_I_LENALLOC(inode);
+ *extoffset = udf_file_entry_alloc_offset(inode);
+ etype = EXTENT_RECORDED_ALLOCATED;
+ break;
+ }
default:
{
udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode));
@@ -1741,7 +1668,8 @@ int udf_next_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
if (*elen)
return etype;
- udf_debug("Empty Extent!\n");
+ udf_debug("Empty Extent, inode=%ld, alloctype=%d, elen=%d, etype=%d, extoffset=%d\n",
+ inode->i_ino, UDF_I_ALLOCTYPE(inode), *elen, etype, *extoffset);
if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
*extoffset -= sizeof(short_ad);
else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
@@ -1974,26 +1902,22 @@ int inode_bmap(struct inode *inode, int block, lb_addr *bloc, Uint32 *extoffset,
return -1;
}
+ *extoffset = udf_file_entry_alloc_offset(inode);
+ *elen = 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)
+ do
{
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;
}
- }
+ } while (lbcount + *elen <= b_off);
+
*offset = (b_off - lbcount) >> inode->i_sb->s_blocksize_bits;
return etype;
@@ -2029,3 +1953,58 @@ long udf_block_map(struct inode *inode, long block)
unlock_kernel();
return ret;
}
+
+int udf_readpage_adinicb (struct dentry *dentry, struct page * page)
+{
+ struct inode *inode = dentry->d_inode;
+
+ struct buffer_head *bh;
+ int block;
+ unsigned long kaddr = 0;
+
+ if (!PageLocked(page))
+ PAGE_BUG(page);
+
+ kaddr = kmap(page);
+ memset((char *)kaddr, 0, PAGE_CACHE_SIZE);
+ block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
+ bh = getblk (inode->i_dev, block, inode->i_sb->s_blocksize);
+ ll_rw_block (READ, 1, &bh);
+ wait_on_buffer(bh);
+ memcpy((char *)kaddr, bh->b_data + udf_ext0_offset(inode),
+ inode->i_size);
+ brelse(bh);
+ SetPageUptodate(page);
+ kunmap(page);
+ UnlockPage(page);
+ return 0;
+}
+
+int udf_writepage_adinicb (struct dentry *dentry, struct page *page)
+{
+ struct inode *inode = dentry->d_inode;
+
+ struct buffer_head *bh;
+ int block;
+ unsigned long kaddr = 0;
+
+ if (!PageLocked(page))
+ BUG();
+
+ kaddr = kmap(page);
+ block = udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0);
+ bh = getblk (inode->i_dev, block, inode->i_sb->s_blocksize);
+ if (!buffer_uptodate(bh))
+ {
+ ll_rw_block (READ, 1, &bh);
+ wait_on_buffer(bh);
+ }
+ memcpy(bh->b_data + udf_ext0_offset(inode), (char *)kaddr,
+ inode->i_size);
+ ll_rw_block (WRITE, 1, &bh);
+ wait_on_buffer(bh);
+ brelse(bh);
+ SetPageUptodate(page);
+ kunmap(page);
+ return 0;
+}
diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c
index dee98ad71..d8993254e 100644
--- a/fs/udf/lowlevel.c
+++ b/fs/udf/lowlevel.c
@@ -15,7 +15,7 @@
* ftp://prep.ai.mit.edu/pub/gnu/GPL
* Each contributing author retains all rights to their own work.
*
- * (C) 1999 Ben Fennema
+ * (C) 1999-2000 Ben Fennema
*
* HISTORY
*
@@ -47,16 +47,21 @@ udf_get_last_session(struct super_block *sb)
vol_desc_start=0;
ms_info.addr_format=CDROM_LBA;
- i=ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
+ i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
+
#define WE_OBEY_THE_WRITTEN_STANDARDS 1
- if (i == 0) {
+
+ 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 {
+ }
+ else
+ {
udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i);
}
return vol_desc_start;
@@ -86,17 +91,20 @@ udf_get_last_block(struct super_block *sb, int *flags)
lblock = 0;
ret = ioctl_by_bdev(bdev, BLKGETSIZE, (unsigned long) &lblock);
- if (!ret && lblock != 0x7FFFFFFF) {
- /* Hard Disk */
+ if (!ret && lblock != 0x7FFFFFFF) /* Hard Disk */
+ {
if (mult)
lblock *= mult;
else if (div)
lblock /= div;
- } else {
- /* CDROM */
+ }
+ else /* CDROM */
+ {
ret = ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock);
}
+
if (!ret && lblock)
return lblock - 1;
- return 0;
+ else
+ return 0;
}
diff --git a/fs/udf/misc.c b/fs/udf/misc.c
index 0b2068015..834727ae8 100644
--- a/fs/udf/misc.c
+++ b/fs/udf/misc.c
@@ -16,8 +16,8 @@
* Each contributing author retains all rights to their own work.
*
* (C) 1998 Dave Boynton
- * (C) 1998-1999 Ben Fennema
- * (C) 1999 Stelias Computing Inc
+ * (C) 1998-2000 Ben Fennema
+ * (C) 1999-2000 Stelias Computing Inc
*
* HISTORY
*
@@ -64,20 +64,6 @@ udf64_high32(Uint64 indat)
return indat >> 32;
}
-uid_t udf_convert_uid(int uidin)
-{
- if ( uidin == -1 )
- return 0;
- return uidin;
-}
-
-gid_t udf_convert_gid(int gidin)
-{
- if ( gidin == -1 )
- return 0;
- return gidin;
-}
-
#if defined(__linux__) && defined(__KERNEL__)
extern struct buffer_head *
@@ -138,7 +124,6 @@ udf_add_extendedattr(struct inode * inode, Uint32 size, Uint32 type,
if (UDF_I_LENALLOC(inode))
{
memmove(&ad[size], ad, UDF_I_LENALLOC(inode));
- UDF_I_EXT0OFFS(inode) += size;
}
if (UDF_I_LENEATTR(inode))
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index ebf344832..1f54833e4 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -15,14 +15,13 @@
* 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
+ * (C) 1998-2000 Ben Fennema
+ * (C) 1999-2000 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
- *
+ * 12/12/98 blf Created. Split out the lookup code from dir.c
+ * 04/19/99 blf link, mknod, symlink support
*/
#include "udfdecl.h"
@@ -153,7 +152,7 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
char *nameptr;
Uint8 lfi;
Uint16 liu;
- loff_t size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2;
+ loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
lb_addr bloc, eloc;
Uint32 extoffset, elen, offset;
struct buffer_head *bh = NULL;
@@ -161,7 +160,7 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
if (!dir)
return NULL;
- f_pos = (UDF_I_EXT0OFFS(dir) >> 2);
+ f_pos = (udf_ext0_offset(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),
@@ -297,6 +296,9 @@ udf_lookup(struct inode *dir, struct dentry *dentry)
struct FileIdentDesc cfi, *fi;
struct udf_fileident_bh fibh;
+ if (dentry->d_name.len > UDF_NAME_LEN)
+ return ERR_PTR(-ENAMETOOLONG);
+
#ifdef UDF_RECOVERY
/* temporary shorthand for specifying files by inode number */
if (!strncmp(dentry->d_name.name, ".B=", 3) )
@@ -336,7 +338,7 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
loff_t f_pos;
int flen;
char *nameptr;
- loff_t size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2;
+ loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
int nfidlen;
Uint8 lfi;
Uint16 liu;
@@ -370,7 +372,7 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
nfidlen = (sizeof(struct FileIdentDesc) + 0 + namelen + 3) & ~3;
- f_pos = (UDF_I_EXT0OFFS(dir) >> 2);
+ f_pos = (udf_ext0_offset(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),
@@ -473,13 +475,13 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
{
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);
+ fibh->soffset -= udf_ext0_offset(dir);
+ fibh->eoffset -= udf_ext0_offset(dir);
+ f_pos -= (udf_ext0_offset(dir) >> 2);
if (fibh->sbh != fibh->ebh)
udf_release_data(fibh->ebh);
udf_release_data(fibh->sbh);
- if (!(fibh->sbh = fibh->ebh = udf_expand_adinicb(dir, &block, 1, err)))
+ if (!(fibh->sbh = fibh->ebh = udf_expand_dir_adinicb(dir, &block, err)))
return NULL;
bloc = UDF_I_LOCATION(dir);
extoffset = udf_file_entry_alloc_offset(dir);
@@ -640,7 +642,7 @@ int udf_create(struct inode *dir, struct dentry *dentry, int mode)
if (!inode)
return err;
- inode->i_op = &udf_file_inode_operations;
+ inode->i_op = &udf_file_inode_operations_adinicb;
inode->i_mode = mode;
mark_inode_dirty(inode);
@@ -682,6 +684,7 @@ int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
goto out;
inode->i_uid = current->fsuid;
+ init_special_inode(inode, mode, rdev);
inode->i_mode = mode;
inode->i_op = NULL;
if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
@@ -702,7 +705,6 @@ int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
mark_inode_dirty(dir);
dir->i_version = ++event;
}
- init_special_inode(inode, mode, rdev);
mark_inode_dirty(inode);
if (fibh.sbh != fibh.ebh)
@@ -734,19 +736,9 @@ int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
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;
- }
+ 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);
if (!fibh.sbh)
{
@@ -809,13 +801,13 @@ static int empty_dir(struct inode *dir)
struct FileIdentDesc *fi, cfi;
struct udf_fileident_bh fibh;
loff_t f_pos;
- loff_t size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2;
+ loff_t size = (udf_ext0_offset(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);
+ f_pos = (udf_ext0_offset(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),
@@ -1170,7 +1162,7 @@ int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
}
if (S_ISDIR(old_inode->i_mode))
{
- Uint32 offset = UDF_I_EXT0OFFS(old_inode);
+ Uint32 offset = udf_ext0_offset(old_inode);
if (new_inode)
{
@@ -1203,6 +1195,14 @@ int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
new_dir->i_version = ++event;
/*
+ * Like most other Unix systems, set the ctime for inodes on a
+ * rename.
+ */
+ old_inode->i_ctime = CURRENT_TIME;
+ UDF_I_UCTIME(old_inode) = CURRENT_UTIME;
+ mark_inode_dirty(old_inode);
+
+ /*
* ok, that's it
*/
ncfi.fileVersionNum = ocfi.fileVersionNum;
diff --git a/fs/udf/partition.c b/fs/udf/partition.c
index ecfabb849..658d2220e 100644
--- a/fs/udf/partition.c
+++ b/fs/udf/partition.c
@@ -30,161 +30,204 @@
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/udf_fs.h>
+#include <linux/malloc.h>
-extern Uint32 udf_get_pblock(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
+inline 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))
+ if (UDF_SB_PARTFUNC(sb, partition))
+ return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset);
+ else
+ return UDF_SB_PARTROOT(sb, partition) + block + offset;
+}
+
+Uint32 udf_get_pblock_virt15(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
+{
+ 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)
{
- 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;
+ 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;
+ }
- index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(Uint32);
+ 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 (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 (!(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;
+ }
- 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 = le32_to_cpu(((Uint32 *)bh->b_data)[index]);
- loc = udf_locked_block_map(UDF_SB_VAT(sb), newblock);
+ udf_release_data(bh);
- 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;
- }
+ if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
+ {
+ udf_debug("recursive call to udf_get_pblock!\n");
+ return 0xFFFFFFFF;
+ }
- loc = le32_to_cpu(((Uint32 *)bh->b_data)[index]);
+ return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
+}
- udf_release_data(bh);
+inline Uint32 udf_get_pblock_virt20(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
+{
+ return udf_get_pblock_virt15(sb, block, partition, offset);
+}
- if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
- {
- udf_debug("recursive call to udf_get_pblock!\n");
- return 0xFFFFFFFF;
- }
+Uint32 udf_get_pblock_spar15(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
+{
+ Uint32 packet = (block + offset) >> UDF_SB_TYPESPAR(sb,partition).s_spar_pshift;
+ Uint32 index = 0;
- 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;
+ if (UDF_SB_TYPESPAR(sb,partition).s_spar_indexsize == 8)
+ index = UDF_SB_TYPESPAR(sb,partition).s_spar_remap.s_spar_remap8[packet];
+ else if (UDF_SB_TYPESPAR(sb,partition).s_spar_indexsize == 16)
+ index = UDF_SB_TYPESPAR(sb,partition).s_spar_remap.s_spar_remap16[packet];
+ else if (UDF_SB_TYPESPAR(sb,partition).s_spar_indexsize == 32)
+ index = UDF_SB_TYPESPAR(sb,partition).s_spar_remap.s_spar_remap32[packet];
- bh = udf_read_tagged(sb, spartable, spartable, &ident);
+ if (index == ((1 << UDF_SB_TYPESPAR(sb,partition).s_spar_indexsize)-1))
+ return UDF_SB_PARTROOT(sb,partition) + block + offset;
- if (!bh)
- {
- printk(KERN_ERR "udf: udf_read_tagged(%p,%d,%d)\n",
- sb, spartable, spartable);
- return 0xFFFFFFFF;
- }
+ packet = UDF_SB_TYPESPAR(sb,partition).s_spar_map[index];
+ return packet + ((block + offset) & ((1 << UDF_SB_TYPESPAR(sb,partition).s_spar_pshift)-1));
+}
+
+void udf_fill_spartable(struct super_block *sb, struct udf_sparing_data *sdata, int partlen)
+{
+ Uint16 ident;
+ Uint32 spartable;
+ int i;
+ struct buffer_head *bh;
+ struct SparingTable *st;
+
+ for (i=0; i<4; i++)
+ {
+ if (!(spartable = sdata->s_spar_loc[i]))
+ continue;
+
+ bh = udf_read_tagged(sb, spartable, spartable, &ident);
+
+ if (!bh)
+ {
+ sdata->s_spar_loc[i] = 0;
+ continue;
+ }
+ if (ident == 0)
+ {
st = (struct SparingTable *)bh->b_data;
- if (ident == 0)
+ if (!strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING)))
{
- if (!strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING)))
- {
- Uint16 rtl = le16_to_cpu(st->reallocationTableLen);
- Uint16 index;
+ SparingEntry *se;
+ Uint16 rtl = le16_to_cpu(st->reallocationTableLen);
+ int index;
- /* If the sparing table span multiple blocks, find out which block we are on */
-
- se = &(st->mapEntry[0]);
+ if (!sdata->s_spar_map)
+ {
+ int num = 1, mapsize;
+ sdata->s_spar_indexsize = 8;
+ while (rtl*sizeof(Uint32) >= (1 << sdata->s_spar_indexsize))
+ {
+ num ++;
+ sdata->s_spar_indexsize <<= 1;
+ }
+ mapsize = (rtl * sizeof(Uint32)) +
+ ((partlen/(1 << sdata->s_spar_pshift)) * sizeof(Uint8) * num);
+ sdata->s_spar_map = kmalloc(mapsize, GFP_KERNEL);
+ sdata->s_spar_remap.s_spar_remap32 = &sdata->s_spar_map[rtl];
+ memset(sdata->s_spar_map, 0xFF, mapsize);
+ }
- if (rtl * sizeof(SparingEntry) + sizeof(struct SparingTable) > sb->s_blocksize)
+ index = sizeof(struct SparingTable);
+ for (i=0; i<rtl; i++)
+ {
+ if (index > 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);
+ bh = udf_tread(sb, ++spartable, sb->s_blocksize);
+ if (!bh)
{
- udf_release_data(bh);
- return le32_to_cpu(se[index].mappedLocation) | (newblock & (plength-1));
+ sdata->s_spar_loc[i] = 0;
+ continue;
}
- else if (le32_to_cpu(se[index-1].origLocation) < packet)
+ index = 0;
+ }
+ se = (SparingEntry *)&(bh->b_data[index]);
+ index += sizeof(SparingEntry);
+
+ if (sdata->s_spar_map[i] == 0xFFFFFFFF)
+ sdata->s_spar_map[i] = le32_to_cpu(se->mappedLocation);
+ else if (sdata->s_spar_map[i] != le32_to_cpu(se->mappedLocation))
+ {
+ udf_debug("Found conflicting Sparing Data (%d vs %d for entry %d)\n",
+ sdata->s_spar_map[i], le32_to_cpu(se->mappedLocation), i);
+ }
+
+ if (le32_to_cpu(se->origLocation) < 0xFFFFFFF0)
+ {
+ int packet = le32_to_cpu(se->origLocation) >> sdata->s_spar_pshift;
+ if (sdata->s_spar_indexsize == 8)
{
- do
+ if (sdata->s_spar_remap.s_spar_remap8[packet] == 0xFF)
+ sdata->s_spar_remap.s_spar_remap8[packet] = i;
+ else if (sdata->s_spar_remap.s_spar_remap8[packet] != i)
{
- 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);
+ udf_debug("Found conflicting Sparing Data (%d vs %d)\n",
+ sdata->s_spar_remap.s_spar_remap8[packet], i);
+ }
}
- }
-
- for (index=0; index<rtl; index++)
- {
- if (le32_to_cpu(se[index].origLocation) == packet)
+ else if (sdata->s_spar_indexsize == 16)
{
- udf_release_data(bh);
- return le32_to_cpu(se[index].mappedLocation) | (newblock & (plength-1));
+ if (sdata->s_spar_remap.s_spar_remap16[packet] == 0xFFFF)
+ sdata->s_spar_remap.s_spar_remap16[packet] = i;
+ else if (sdata->s_spar_remap.s_spar_remap16[packet] != i)
+ {
+ udf_debug("Found conflicting Sparing Data (%d vs %d)\n",
+ sdata->s_spar_remap.s_spar_remap16[packet], i);
+ }
}
- else if (le32_to_cpu(se[index].origLocation) > packet)
+ else if (sdata->s_spar_indexsize == 32)
{
- udf_release_data(bh);
- return newblock;
+ if (sdata->s_spar_remap.s_spar_remap32[packet] == 0xFFFFFFFF)
+ sdata->s_spar_remap.s_spar_remap32[packet] = i;
+ else if (sdata->s_spar_remap.s_spar_remap32[packet] != i)
+ {
+ udf_debug("Found conflicting Sparing Data (%d vs %d)\n",
+ sdata->s_spar_remap.s_spar_remap32[packet], i);
+ }
}
}
-
- udf_release_data(bh);
- return newblock;
}
}
- udf_release_data(bh);
}
+ 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
index aba702b57..272b9eacb 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -26,7 +26,8 @@
* Each contributing author retains all rights to their own work.
*
* (C) 1998 Dave Boynton
- * (C) 1998-1999 Ben Fennema
+ * (C) 1998-2000 Ben Fennema
+ * (C) 2000 Stelias Computing Inc
*
* HISTORY
*
@@ -91,29 +92,27 @@ 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 */
+ "udf", /* name */
FS_REQUIRES_DEV, /* fs_flags */
udf_read_super, /* read_super */
- NULL /* next */
+ NULL /* next */
};
/* Superblock operations */
static struct super_operations udf_sb_ops =
{
udf_read_inode, /* read_inode */
-#ifdef CONFIG_UDF_RW
+#if CONFIG_UDF_RW == 1
udf_write_inode, /* write_inode */
#else
NULL, /* write_inode */
#endif
udf_put_inode, /* put_inode */
-#ifdef CONFIG_UDF_RW
+#if CONFIG_UDF_RW == 1
udf_delete_inode, /* delete_inode */
#else
NULL, /* delete_inode */
@@ -130,7 +129,6 @@ static struct super_operations udf_sb_ops =
struct udf_options
{
unsigned char novrs;
- unsigned char utf8;
unsigned int blocksize;
unsigned int session;
unsigned int lastblock;
@@ -143,7 +141,6 @@ struct udf_options
mode_t umask;
gid_t gid;
uid_t uid;
- char *iocharset;
};
#if defined(MODULE)
@@ -194,8 +191,8 @@ int __init init_udf_fs(void)
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));
+ printk(KERN_ERR "udf: Kernel has room for %u bytes, udf needs %lu\n",
+ size, (unsigned long)sizeof(struct udf_sb_info));
return 0;
}
}
@@ -217,8 +214,6 @@ int __init init_udf_fs(void)
* 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:
*
@@ -267,7 +262,6 @@ udf_parse_options(char *options, struct udf_options *uopt)
uopt->volume = 0xFFFFFFFF;
uopt->rootdir = 0xFFFFFFFF;
uopt->fileset = 0xFFFFFFFF;
- uopt->iocharset = NULL;
if (!options)
return 1;
@@ -280,8 +274,6 @@ udf_parse_options(char *options, struct udf_options *uopt)
*(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)
@@ -310,15 +302,6 @@ udf_parse_options(char *options, struct udf_options *uopt)
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",
@@ -344,7 +327,6 @@ udf_remount_fs(struct super_block *sb, int *flags, char *options)
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;
@@ -353,7 +335,6 @@ udf_remount_fs(struct super_block *sb, int *flags, char *options)
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;
@@ -841,6 +822,9 @@ udf_load_partdesc(struct super_block *sb, struct buffer_head *bh)
UDF_SB_PARTROOT(sb,i) = le32_to_cpu(p->partitionStartingLocation) + UDF_SB_SESSION(sb);
UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap = 0xFFFFFFFF;
+ if (UDF_SB_PARTTYPE(sb,i) == UDF_SPARABLE_MAP15)
+ udf_fill_spartable(sb, &UDF_SB_TYPESPAR(sb,i), UDF_SB_PARTLEN(sb,i));
+
if (!strcmp(p->partitionContents.ident, PARTITION_CONTENTS_NSR02) ||
!strcmp(p->partitionContents.ident, PARTITION_CONTENTS_NSR03))
{
@@ -882,7 +866,7 @@ static int
udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, lb_addr *fileset)
{
struct LogicalVolDesc *lvd;
- int i, offset;
+ int i, j, offset;
Uint8 type;
lvd = (struct LogicalVolDesc *)bh->b_data;
@@ -902,6 +886,7 @@ udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, lb_addr *fi
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);
+ UDF_SB_PARTFUNC(sb,i) = NULL;
}
else if (type == 2)
{
@@ -909,16 +894,29 @@ udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, lb_addr *fi
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;
+ UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_virt15;
+ }
else if (le16_to_cpu(((Uint16 *)upm2->partIdent.identSuffix)[0]) == 0x0200)
+ {
UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP20;
+ UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_virt20;
+ }
}
else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE)))
{
+ int plen;
+
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]);
+ plen = le16_to_cpu(spm->packetLength);
+ UDF_SB_TYPESPAR(sb,i).s_spar_pshift = 0;
+ while (plen >>= 1)
+ UDF_SB_TYPESPAR(sb,i).s_spar_pshift ++;
+ for (j=0; j<spm->numSparingTables; j++)
+ UDF_SB_TYPESPAR(sb,i).s_spar_loc[j] = le32_to_cpu(spm->locSparingTable[j]);
+ UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_spar15;
}
else
{
@@ -1190,7 +1188,7 @@ udf_load_partition(struct super_block *sb, lb_addr *fileset)
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_start_offset = udf_ext0_offset(UDF_SB_VAT(sb));
UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size - 36) >> 2;
}
else if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP20)
@@ -1201,8 +1199,8 @@ udf_load_partition(struct super_block *sb, lb_addr *fileset)
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));
+ le16_to_cpu(((struct VirtualAllocationTable20 *)bh->b_data + udf_ext0_offset(UDF_SB_VAT(sb)))->lengthHeader) +
+ udf_ext0_offset(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) >> 2;
udf_release_data(bh);
@@ -1218,7 +1216,7 @@ udf_load_partition(struct super_block *sb, lb_addr *fileset)
static void udf_open_lvid(struct super_block *sb)
{
-#ifdef CONFIG_UDF_RW
+#if CONFIG_UDF_RW == 1
if (UDF_SB_LVIDBH(sb))
{
int i;
@@ -1247,7 +1245,7 @@ static void udf_open_lvid(struct super_block *sb)
static void udf_close_lvid(struct super_block *sb)
{
-#ifdef CONFIG_UDF_RW
+#if CONFIG_UDF_RW == 1
if (UDF_SB_LVIDBH(sb) &&
UDF_SB_LVID(sb)->integrityType == INTEGRITY_TYPE_OPEN)
{
@@ -1301,10 +1299,9 @@ udf_read_super(struct super_block *sb, void *options, int silent)
int i;
uopt.flags = 0;
- uopt.uid = 0;
- uopt.gid = 0;
+ uopt.uid = -1;
+ uopt.gid = -1;
uopt.umask = 0;
- uopt.utf8 = 0;
/* Lock the module in memory (if applicable) */
MOD_INC_USE_COUNT;
@@ -1328,7 +1325,6 @@ udf_read_super(struct super_block *sb, void *options, int silent)
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))
@@ -1356,20 +1352,6 @@ udf_read_super(struct super_block *sb, void *options, int silent)
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->dq_op = NULL;
@@ -1405,7 +1387,8 @@ udf_read_super(struct super_block *sb, void *options, int silent)
{
timestamp ts;
udf_time_to_stamp(&ts, UDF_SB_RECORDTIME(sb), 0);
- udf_info("Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
+ udf_info("UDF %s (%s) Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
+ UDFFS_VERSION, UDFFS_DATE,
UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute,
ts.typeAndTimezone);
}
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
index 63ebb5713..6e5dd233a 100644
--- a/fs/udf/symlink.c
+++ b/fs/udf/symlink.c
@@ -15,7 +15,7 @@
* ftp://prep.ai.mit.edu/pub/gnu/GPL
* Each contributing author retains all rights to their own work.
*
- * (C) 1998-1999 Ben Fennema
+ * (C) 1998-2000 Ben Fennema
* (C) 1999 Stelias Computing Inc
*
* HISTORY
@@ -39,14 +39,17 @@
static void udf_pc_to_char(char *from, int fromlen, char *to)
{
struct PathComponent *pc;
- int elen = 0, len = 0;
+ int elen = 0;
char *p = to;
- while (elen < fromlen) {
+ while (elen < fromlen)
+ {
pc = (struct PathComponent *)(from + elen);
- switch (pc->componentType) {
+ switch (pc->componentType)
+ {
case 1:
- if (pc->lengthComponentIdent == 0) {
+ if (pc->lengthComponentIdent == 0)
+ {
p = to;
*p++ = '/';
}
@@ -61,17 +64,16 @@ static void udf_pc_to_char(char *from, int fromlen, char *to)
/* that would be . - just ignore */
break;
case 5:
- memcpy(p+len, pc->componentIdent,
- pc->lengthComponentIdent);
+ memcpy(p, pc->componentIdent, pc->lengthComponentIdent);
p += pc->lengthComponentIdent;
*p++ = '/';
}
elen += sizeof(struct PathComponent) + pc->lengthComponentIdent;
}
-
- if (p>to+1) {
+ if (p > to+1)
p[-1] = '\0';
- }
+ else
+ p[0] = '\0';
}
static int udf_symlink_filler(struct dentry * dentry, struct page *page)
@@ -79,20 +81,20 @@ static int udf_symlink_filler(struct dentry * dentry, struct page *page)
struct inode *inode = dentry->d_inode;
struct buffer_head *bh = NULL;
char *symlink;
- int err;
-
- char *p = (char*)kmap(page);
+ int err = -EIO;
+ char *p = (char *)kmap(page);
- err = -EIO;
- 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 (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)
goto out;
symlink = bh->b_data + udf_file_entry_alloc_offset(inode);
- } else {
+ }
+ else
+ {
bh = bread(inode->i_dev, udf_block_map(inode, 0),
inode->i_sb->s_blocksize);
@@ -104,6 +106,7 @@ static int udf_symlink_filler(struct dentry * dentry, struct page *page)
udf_pc_to_char(symlink, inode->i_size, p);
udf_release_data(bh);
+
SetPageUptodate(page);
kunmap(page);
UnlockPage(page);
@@ -112,14 +115,29 @@ out:
SetPageError(page);
kunmap(page);
UnlockPage(page);
- return -EIO;
+ return err;
}
/*
* symlinks can't do much...
*/
struct inode_operations udf_symlink_inode_operations = {
- readlink: page_readlink,
- follow_link: page_follow_link,
- readpage: udf_symlink_filler,
+ NULL, /* no file-operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ page_readlink, /* readlink */
+ page_follow_link, /* follow_link */
+ NULL, /* get_block */
+ udf_symlink_filler, /* readpage */
+ NULL, /* writepage */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL /* revalidate */
};
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index 1bf6e4cee..4054da721 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -15,7 +15,7 @@
* ftp://prep.ai.mit.edu/pub/gnu/GPL
* Each contributing author retains all rights to their own work.
*
- * (C) 1999 Ben Fennema
+ * (C) 1999-2000 Ben Fennema
* (C) 1999 Stelias Computing Inc
*
* HISTORY
@@ -33,32 +33,29 @@
#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 eloc, Uint8 etype, Uint32 elen, struct buffer_head **bh, Uint32 offset)
{
lb_addr neloc = { 0, 0 };
- int nelen = 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_bits;
if (offset)
{
- nelen = ((offset - 1) << inode->i_sb->s_blocksize_bits) +
- (inode->i_size & (inode->i_sb->s_blocksize - 1));
+ nelen = (etype << 30) |
+ (((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));
+ if (etype == EXTENT_RECORDED_ALLOCATED)
+ 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);
+ if (etype != EXTENT_NOT_RECORDED_NOT_ALLOCATED)
+ udf_free_blocks(inode, eloc, offset, last_block - offset);
}
-static void trunc(struct inode * inode)
+void udf_trunc(struct inode * inode)
{
lb_addr bloc, eloc, neloc = { 0, 0 };
Uint32 extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc;
@@ -77,7 +74,7 @@ static void trunc(struct inode * inode)
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);
+ extent_trunc(inode, bloc, &extoffset, eloc, etype, elen, &bh, offset);
if (offset)
lenalloc = extoffset;
@@ -124,10 +121,8 @@ static void trunc(struct inode * inode)
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);
+ extent_trunc(inode, bloc, &extoffset, eloc, etype, elen, &bh, 0);
}
if (lelen)
@@ -151,8 +146,6 @@ static void trunc(struct inode * inode)
}
else if (inode->i_size)
{
- lb_addr e0loc = UDF_I_LOCATION(inode);
- Uint32 ext0offset = udf_file_entry_alloc_offset(inode);
char tetype;
if (offset)
@@ -164,8 +157,6 @@ static void trunc(struct inode * inode)
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
@@ -176,18 +167,11 @@ static void trunc(struct inode * inode)
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);
}
}
@@ -204,12 +188,7 @@ void udf_truncate(struct inode * inode)
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return;
- if (!UDF_I_EXT0OFFS(inode))
- {
- udf_discard_prealloc(inode);
-
- trunc(inode);
- }
+ udf_trunc(inode);
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
@@ -223,6 +202,8 @@ void udf_truncate_adinicb(struct inode * inode)
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return;
+ UDF_I_LENALLOC(inode) = inode->i_size;
+
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
index 8b9038296..4d1f64c85 100644
--- a/fs/udf/udf_i.h
+++ b/fs/udf/udf_i.h
@@ -1,11 +1,8 @@
#ifndef __LINUX_UDF_I_H
#define __LINUX_UDF_I_H
-#define UDF_I(X) (&((X)->u.udf_i))
+#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 )
@@ -13,8 +10,6 @@
#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 )
diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
index 310ba4aef..5fab514bc 100644
--- a/fs/udf/udf_sb.h
+++ b/fs/udf/udf_sb.h
@@ -24,6 +24,7 @@
{\
UDF_SB_NUMPARTS(X) = Y;\
UDF_SB_PARTMAPS(X) = kmalloc(sizeof(struct udf_part_map) * Y, GFP_KERNEL);\
+ memset(UDF_SB_PARTMAPS(X), 0x00, sizeof(struct udf_part_map) * Y);\
}
#define IS_STRICT(X) ( UDF_SB(X)->s_flags & UDF_FLAG_STRICT )
@@ -43,9 +44,7 @@
#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] )
@@ -59,5 +58,6 @@
#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 )
+#define UDF_SB_PARTFUNC(X,Y) ( UDF_SB_PARTMAPS(X)[Y].s_partition_func )
#endif /* __LINUX_UDF_SB_H */
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index f50ca705c..171cd0d75 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -1,7 +1,7 @@
#ifndef __UDF_DECL_H
#define __UDF_DECL_H
-#define UDF_VERSION_NOTICE "v0.8.9.4"
+#define UDF_VERSION_NOTICE "v0.9.0"
#include <linux/udf_167.h>
#include <linux/udf_udf.h>
@@ -39,6 +39,12 @@
sizeof(struct ExtendedFileEntry) :\
sizeof(struct FileEntry)) + UDF_I_LENEATTR(inode))
+#define udf_ext0_offset(inode)\
+ (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB ?\
+ udf_file_entry_alloc_offset(inode) : 0)
+
+#define udf_get_lb_pblock(sb,loc,offset) udf_get_pblock((sb), (loc).logicalBlockNum, (loc).partitionReferenceNum, (offset))
+
#else
#include <sys/types.h>
@@ -128,9 +134,12 @@ extern int udf_ioctl(struct inode *, struct file *, unsigned int, unsigned long)
/* inode.c */
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 void udf_expand_file_adinicb(struct file *, int, int *);
+extern struct buffer_head * udf_expand_dir_adinicb(struct inode *, 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 int udf_readpage_adinicb (struct dentry *, struct page *);
+extern int udf_writepage_adinicb (struct dentry *, struct page *);
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 *);
@@ -163,7 +172,10 @@ extern unsigned int udf_get_last_block(struct super_block *, int *);
/* partition.c */
extern Uint32 udf_get_pblock(struct super_block *, Uint32, Uint16, Uint32);
-extern Uint32 udf_get_lb_pblock(struct super_block *, lb_addr, Uint32);
+extern Uint32 udf_get_pblock_virt15(struct super_block *, Uint32, Uint16, Uint32);
+extern Uint32 udf_get_pblock_virt20(struct super_block *, Uint32, Uint16, Uint32);
+extern Uint32 udf_get_pblock_spar15(struct super_block *, Uint32, Uint16, Uint32);
+extern void udf_fill_spartable(struct super_block *, struct udf_sparing_data *, int);
/* unicode.c */
extern int udf_get_filename(Uint8 *, Uint8 *, int);
@@ -173,6 +185,7 @@ extern void udf_free_inode(struct inode *);
extern struct inode * udf_new_inode (const struct inode *, int, int *);
/* truncate.c */
+extern void udf_trunc(struct inode *);
extern void udf_truncate(struct inode *);
extern void udf_truncate_adinicb(struct inode *);
@@ -181,6 +194,7 @@ 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 *);
+extern int udf_sync_file_adinicb(struct file *, struct dentry *);
/* directory.c */
extern Uint8 * udf_filead_read(struct inode *, Uint8 *, Uint8, lb_addr, int *, int *, struct buffer_head **, int *);
@@ -207,8 +221,6 @@ extern int udf_UTF8toCS0(dstring *, struct ustr *, int);
extern Uint16 udf_crc(Uint8 *, Uint32, Uint16);
/* misc.c */
-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 void udf_update_tag(char *, int);
diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c
index 3fa925f6b..b2a9e3462 100644
--- a/fs/udf/udftime.c
+++ b/fs/udf/udftime.c
@@ -139,7 +139,7 @@ udf_time_to_stamp(timestamp *dest, time_t tv_sec, long tv_usec)
gettimeofday(&tv, &sys_tz);
#endif
- offset = (-sys_tz.tz_minuteswest + (sys_tz.tz_dsttime ? 60 : 0));
+ offset = (-sys_tz.tz_minuteswest);
if (!dest)
return NULL;
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
index 6cf63164d..29801728d 100644
--- a/fs/udf/unicode.c
+++ b/fs/udf/unicode.c
@@ -38,24 +38,24 @@ 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);
+ memcpy(dest+1, src->u_name, src->u_len);
dest[0] = src->u_cmpID;
- return src->u_len;
+ return src->u_len + 1;
}
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;
+ memcpy(dest, src->u_name, src->u_len);
+ return src->u_len;
}
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;
+ dest[dlength-1] = src->u_len + 1;
return dlength;
}
else
@@ -69,8 +69,8 @@ int udf_dchars_to_ustr(struct ustr *dest, const Uint8 *src, int strlen)
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;
+ dest->u_len = strlen-1;
+ return strlen-1;
}
int udf_char_to_ustr(struct ustr *dest, const Uint8 *src, int strlen)
@@ -80,8 +80,8 @@ int udf_char_to_ustr(struct ustr *dest, const Uint8 *src, int strlen)
memset(dest, 0, sizeof(struct ustr));
memcpy(dest->u_name, src, strlen);
dest->u_cmpID = 0x08;
- dest->u_len = strlen + 1;
- return strlen + 1;
+ dest->u_len = strlen;
+ return strlen;
}
@@ -182,38 +182,21 @@ int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i)
/* 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) {
+ 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 {
+ }
+ 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;
@@ -259,34 +242,49 @@ int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
try_again:
utf_char = 0U;
utf_cnt = 0U;
- for (i = 0U; i < utf->u_len; i++) {
- c = (unsigned)utf->u_name[i];
+ for (i = 0U; i < utf->u_len; i++)
+ {
+ c = (Uint8)utf->u_name[i];
/* Complete a multi-byte UTF-8 character */
- if (utf_cnt) {
+ if (utf_cnt)
+ {
utf_char = (utf_char << 6) | (c & 0x3fU);
if (--utf_cnt)
continue;
- } else {
+ }
+ else
+ {
/* Check for a multi-byte UTF-8 character */
- if (c & 0x80U) {
+ if (c & 0x80U)
+ {
/* Start a multi-byte UTF-8 character */
- if ((c & 0xe0U) == 0xc0U) {
+ if ((c & 0xe0U) == 0xc0U)
+ {
utf_char = c & 0x1fU;
utf_cnt = 1;
- } else if ((c & 0xf0U) == 0xe0U) {
+ }
+ else if ((c & 0xf0U) == 0xe0U)
+ {
utf_char = c & 0x0fU;
utf_cnt = 2;
- } else if ((c & 0xf8U) == 0xf0U) {
+ }
+ else if ((c & 0xf8U) == 0xf0U)
+ {
utf_char = c & 0x07U;
utf_cnt = 3;
- } else if ((c & 0xfcU) == 0xf8U) {
+ }
+ else if ((c & 0xfcU) == 0xf8U)
+ {
utf_char = c & 0x03U;
utf_cnt = 4;
- } else if ((c & 0xfeU) == 0xfcU) {
+ }
+ else if ((c & 0xfeU) == 0xfcU)
+ {
utf_char = c & 0x01U;
utf_cnt = 5;
- } else
+ }
+ else
goto error_out;
continue;
} else
@@ -295,8 +293,10 @@ try_again:
}
/* Choose no compression if necessary */
- if (utf_char > max_val) {
- if ( 0xffU == max_val ) {
+ if (utf_char > max_val)
+ {
+ if ( 0xffU == max_val )
+ {
max_val = 0xffffU;
ocu[0] = (Uint8)0x10U;
goto try_again;
@@ -305,11 +305,15 @@ try_again:
}
if (max_val == 0xffffU)
+ {
ocu[++u_len] = (Uint8)(utf_char >> 8);
+ }
ocu[++u_len] = (Uint8)(utf_char & 0xffU);
}
- if (utf_cnt) {
+
+ if (utf_cnt)
+ {
error_out:
#ifdef __KERNEL__
printk(KERN_ERR "udf: bad UTF-8 character\n");
@@ -317,8 +321,8 @@ error_out:
return 0;
}
- ocu[length - 1] = (Uint8)u_len;
- return u_len;
+ ocu[length - 1] = (Uint8)u_len + 1;
+ return u_len + 1;
}
#ifdef __KERNEL__