summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-23 00:40:54 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-23 00:40:54 +0000
commit529c593ece216e4aaffd36bd940cb94f1fa63129 (patch)
tree78f1c0b805f5656aa7b0417a043c5346f700a2cf /fs
parent0bd079751d25808d1972baee5c4eaa1db2227257 (diff)
Merge with 2.3.43. I did ignore all modifications to the qlogicisp.c
driver due to the Origin A64 hacks.
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.in3
-rw-r--r--fs/adfs/Makefile2
-rw-r--r--fs/adfs/adfs.h134
-rw-r--r--fs/adfs/dir.c505
-rw-r--r--fs/adfs/dir_f.c479
-rw-r--r--fs/adfs/dir_f.h61
-rw-r--r--fs/adfs/dir_fplus.c182
-rw-r--r--fs/adfs/dir_fplus.h41
-rw-r--r--fs/adfs/file.c43
-rw-r--r--fs/adfs/inode.c475
-rw-r--r--fs/adfs/map.c336
-rw-r--r--fs/adfs/namei.c113
-rw-r--r--fs/adfs/super.c398
-rw-r--r--fs/affs/dir.c22
-rw-r--r--fs/affs/file.c70
-rw-r--r--fs/affs/inode.c12
-rw-r--r--fs/affs/namei.c9
-rw-r--r--fs/affs/symlink.c4
-rw-r--r--fs/autofs/dir.c20
-rw-r--r--fs/autofs/init.c4
-rw-r--r--fs/autofs/root.c18
-rw-r--r--fs/autofs4/autofs_i.h2
-rw-r--r--fs/autofs4/inode.c3
-rw-r--r--fs/autofs4/waitq.c2
-rw-r--r--fs/bad_inode.c29
-rw-r--r--fs/bfs/bfs_defs.h4
-rw-r--r--fs/bfs/dir.c36
-rw-r--r--fs/bfs/file.c159
-rw-r--r--fs/bfs/inode.c94
-rw-r--r--fs/binfmt_elf.c10
-rw-r--r--fs/block_dev.c58
-rw-r--r--fs/buffer.c771
-rw-r--r--fs/coda/cnode.c119
-rw-r--r--fs/coda/coda_linux.c2
-rw-r--r--fs/coda/dir.c75
-rw-r--r--fs/coda/file.c146
-rw-r--r--fs/coda/inode.c21
-rw-r--r--fs/coda/pioctl.c18
-rw-r--r--fs/coda/psdev.c38
-rw-r--r--fs/coda/symlink.c4
-rw-r--r--fs/coda/sysctl.c7
-rw-r--r--fs/coda/upcall.c74
-rw-r--r--fs/cramfs/inflate/zconf.h4
-rw-r--r--fs/cramfs/inode.c144
-rw-r--r--fs/devices.c2
-rw-r--r--fs/devpts/root.c20
-rw-r--r--fs/efs/dir.c30
-rw-r--r--fs/efs/file.c31
-rw-r--r--fs/efs/inode.c18
-rw-r--r--fs/efs/symlink.c4
-rw-r--r--fs/exec.c2
-rw-r--r--fs/ext2/dir.c24
-rw-r--r--fs/ext2/file.c81
-rw-r--r--fs/ext2/fsync.c5
-rw-r--r--fs/ext2/inode.c44
-rw-r--r--fs/ext2/namei.c4
-rw-r--r--fs/ext2/symlink.c10
-rw-r--r--fs/fat/cache.c2
-rw-r--r--fs/fat/dir.c15
-rw-r--r--fs/fat/file.c53
-rw-r--r--fs/fat/inode.c34
-rw-r--r--fs/fat/misc.c2
-rw-r--r--fs/fifo.c2
-rw-r--r--fs/hfs/dir_cap.c53
-rw-r--r--fs/hfs/dir_dbl.c23
-rw-r--r--fs/hfs/dir_nat.c32
-rw-r--r--fs/hfs/file.c23
-rw-r--r--fs/hfs/file_cap.c21
-rw-r--r--fs/hfs/file_hdr.c22
-rw-r--r--fs/hfs/hfs.h3
-rw-r--r--fs/hfs/inode.c31
-rw-r--r--fs/hpfs/dir.c4
-rw-r--r--fs/hpfs/file.c62
-rw-r--r--fs/hpfs/hpfs_fn.h4
-rw-r--r--fs/hpfs/inode.c61
-rw-r--r--fs/hpfs/namei.c11
-rw-r--r--fs/inode.c15
-rw-r--r--fs/ioctl.c15
-rw-r--r--fs/isofs/Makefile2
-rw-r--r--fs/isofs/dir.c26
-rw-r--r--fs/isofs/file.c30
-rw-r--r--fs/isofs/inode.c25
-rw-r--r--fs/isofs/rock.c6
-rw-r--r--fs/isofs/symlink.c27
-rw-r--r--fs/lockd/svc.c14
-rw-r--r--fs/lockd/xdr.c4
-rw-r--r--fs/minix/Makefile2
-rw-r--r--fs/minix/dir.c22
-rw-r--r--fs/minix/file.c51
-rw-r--r--fs/minix/fsync.c17
-rw-r--r--fs/minix/inode.c50
-rw-r--r--fs/minix/namei.c4
-rw-r--r--fs/minix/symlink.c22
-rw-r--r--fs/msdos/namei.c8
-rw-r--r--fs/namei.c9
-rw-r--r--fs/ncpfs/dir.c17
-rw-r--r--fs/ncpfs/file.c19
-rw-r--r--fs/ncpfs/inode.c5
-rw-r--r--fs/ncpfs/symlink.c4
-rw-r--r--fs/nfs/dir.c18
-rw-r--r--fs/nfs/file.c52
-rw-r--r--fs/nfs/inode.c5
-rw-r--r--fs/nfs/write.c2
-rw-r--r--fs/nfsd/nfsctl.c8
-rw-r--r--fs/nfsd/vfs.c2
-rw-r--r--fs/ntfs/fs.c123
-rw-r--r--fs/open.c15
-rw-r--r--fs/openpromfs/inode.c58
-rw-r--r--fs/partitions/check.c4
-rw-r--r--fs/partitions/mac.c54
-rw-r--r--fs/pipe.c126
-rw-r--r--fs/proc/Makefile3
-rw-r--r--fs/proc/array.c3
-rw-r--r--fs/proc/base.c44
-rw-r--r--fs/proc/generic.c11
-rw-r--r--fs/proc/kcore.c10
-rw-r--r--fs/proc/kmsg.c15
-rw-r--r--fs/proc/omirr.c279
-rw-r--r--fs/proc/proc_misc.c8
-rw-r--r--fs/proc/procfs_syms.c3
-rw-r--r--fs/proc/root.c5
-rw-r--r--fs/qnx4/Makefile3
-rw-r--r--fs/qnx4/file.c129
-rw-r--r--fs/qnx4/fsync.c3
-rw-r--r--fs/qnx4/inode.c40
-rw-r--r--fs/qnx4/symlinks.c26
-rw-r--r--fs/romfs/inode.c65
-rw-r--r--fs/select.c149
-rw-r--r--fs/smbfs/dir.c18
-rw-r--r--fs/smbfs/file.c50
-rw-r--r--fs/smbfs/inode.c5
-rw-r--r--fs/stat.c2
-rw-r--r--fs/super.c5
-rw-r--r--fs/sysv/Makefile3
-rw-r--r--fs/sysv/dir.c22
-rw-r--r--fs/sysv/file.c53
-rw-r--r--fs/sysv/fsync.c4
-rw-r--r--fs/sysv/inode.c38
-rw-r--r--fs/sysv/namei.c4
-rw-r--r--fs/sysv/symlink.c26
-rw-r--r--fs/udf/dir.c24
-rw-r--r--fs/udf/file.c229
-rw-r--r--fs/udf/fsync.c8
-rw-r--r--fs/udf/inode.c155
-rw-r--r--fs/udf/namei.c6
-rw-r--r--fs/udf/symlink.c21
-rw-r--r--fs/udf/truncate.c19
-rw-r--r--fs/udf/udfdecl.h9
-rw-r--r--fs/ufs/dir.c17
-rw-r--r--fs/ufs/file.c85
-rw-r--r--fs/ufs/inode.c44
-rw-r--r--fs/ufs/namei.c4
-rw-r--r--fs/ufs/symlink.c10
-rw-r--r--fs/umsdos/Makefile3
-rw-r--r--fs/umsdos/dir.c22
-rw-r--r--fs/umsdos/inode.c3
-rw-r--r--fs/umsdos/rdir.c22
-rw-r--r--fs/umsdos/symlink.c22
-rw-r--r--fs/vfat/namei.c8
159 files changed, 3957 insertions, 4125 deletions
diff --git a/fs/Config.in b/fs/Config.in
index 085e191cb..934a7a70a 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -15,8 +15,7 @@ tristate 'Amiga FFS filesystem support' CONFIG_AFFS_FS
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
+dep_tristate 'BFS filesystem support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL
# msdos filesystems
tristate 'DOS FAT fs support' CONFIG_FAT_FS
diff --git a/fs/adfs/Makefile b/fs/adfs/Makefile
index 0764629fe..6ce002004 100644
--- a/fs/adfs/Makefile
+++ b/fs/adfs/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile.
O_TARGET := adfs.o
-O_OBJS := dir.o file.o inode.o map.o namei.o super.o
+O_OBJS := dir.o dir_f.o dir_fplus.o file.o inode.o map.o super.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
new file mode 100644
index 000000000..abda2e2d0
--- /dev/null
+++ b/fs/adfs/adfs.h
@@ -0,0 +1,134 @@
+/* Internal data structures for ADFS */
+
+#define ADFS_FREE_FRAG 0
+#define ADFS_BAD_FRAG 1
+#define ADFS_ROOT_FRAG 2
+
+#define ADFS_NDA_OWNER_READ (1 << 0)
+#define ADFS_NDA_OWNER_WRITE (1 << 1)
+#define ADFS_NDA_LOCKED (1 << 2)
+#define ADFS_NDA_DIRECTORY (1 << 3)
+#define ADFS_NDA_EXECUTE (1 << 4)
+#define ADFS_NDA_PUBLIC_READ (1 << 5)
+#define ADFS_NDA_PUBLIC_WRITE (1 << 6)
+
+#include "dir_f.h"
+
+/*
+ * Directory handling
+ */
+struct adfs_dir {
+ struct super_block *sb;
+
+ int nr_buffers;
+ struct buffer_head *bh[4];
+ unsigned int pos;
+ unsigned int parent_id;
+
+ struct adfs_dirheader dirhead;
+ union adfs_dirtail dirtail;
+};
+
+/*
+ * This is the overall maximum name length
+ */
+#define ADFS_MAX_NAME_LEN 256
+struct object_info {
+ __u32 parent_id; /* parent object id */
+ __u32 file_id; /* object id */
+ __u32 loadaddr; /* load address */
+ __u32 execaddr; /* execution address */
+ __u32 size; /* size */
+ __u8 attr; /* RISC OS attributes */
+ unsigned char name_len; /* name length */
+ char name[ADFS_MAX_NAME_LEN];/* file name */
+};
+
+struct adfs_dir_ops {
+ int (*read)(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir);
+ int (*setpos)(struct adfs_dir *dir, unsigned int fpos);
+ int (*getnext)(struct adfs_dir *dir, struct object_info *obj);
+ int (*update)(struct adfs_dir *dir, struct object_info *obj);
+ int (*create)(struct adfs_dir *dir, struct object_info *obj);
+ int (*remove)(struct adfs_dir *dir, struct object_info *obj);
+ void (*free)(struct adfs_dir *dir);
+};
+
+struct adfs_discmap {
+ struct buffer_head *dm_bh;
+ __u32 dm_startblk;
+ unsigned int dm_startbit;
+ unsigned int dm_endbit;
+};
+
+/* dir stuff */
+
+
+/* Inode stuff */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+int adfs_get_block(struct inode *inode, long block,
+ struct buffer_head *bh, int create);
+#else
+int adfs_bmap(struct inode *inode, int block);
+#endif
+struct inode *adfs_iget(struct super_block *sb, struct object_info *obj);
+void adfs_read_inode(struct inode *inode);
+void adfs_write_inode(struct inode *inode);
+int adfs_notify_change(struct dentry *dentry, struct iattr *attr);
+
+/* map.c */
+extern int adfs_map_lookup(struct super_block *sb, int frag_id, int offset);
+extern unsigned int adfs_map_free(struct super_block *sb);
+
+/* Misc */
+void __adfs_error(struct super_block *sb, const char *function,
+ const char *fmt, ...);
+#define adfs_error(sb, fmt...) __adfs_error(sb, __FUNCTION__, fmt)
+
+/* namei.c */
+extern struct dentry *adfs_lookup(struct inode *dir, struct dentry *dentry);
+
+/* super.c */
+
+/*
+ * Inodes and file operations
+ */
+
+/* dir_*.c */
+extern struct inode_operations adfs_dir_inode_operations;
+extern struct adfs_dir_ops adfs_f_dir_ops;
+extern struct adfs_dir_ops adfs_fplus_dir_ops;
+
+extern int adfs_dir_update(struct super_block *sb, struct object_info *obj);
+
+/* file.c */
+extern struct inode_operations adfs_file_inode_operations;
+
+extern inline __u32 signed_asl(__u32 val, signed int shift)
+{
+ if (shift >= 0)
+ val <<= shift;
+ else
+ val >>= -shift;
+ return val;
+}
+
+/*
+ * Calculate the address of a block in an object given the block offset
+ * and the object identity.
+ *
+ * The root directory ID should always be looked up in the map [3.4]
+ */
+extern inline int
+__adfs_block_map(struct super_block *sb, unsigned int object_id,
+ unsigned int block)
+{
+ if (object_id & 255) {
+ unsigned int off;
+
+ off = (object_id & 255) - 1;
+ block += off << sb->u.adfs_sb.s_log2sharesize;
+ }
+
+ return adfs_map_lookup(sb, object_id >> 8, block);
+}
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index a65f5c168..140e28598 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -1,345 +1,302 @@
/*
- * linux/fs/adfs/dir.c
+ * linux/fs/adfs/dir.c
*
- * Copyright (C) 1997 Russell King
+ * Copyright (C) 1999 Russell King
+ *
+ * Common directory handling for ADFS
*/
-
+#include <linux/version.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/adfs_fs.h>
#include <linux/sched.h>
#include <linux/stat.h>
-static ssize_t adfs_dirread (struct file *filp, char *buf,
- size_t siz, loff_t *ppos)
-{
- return -EISDIR;
-}
-
-static int adfs_readdir (struct file *, void *, filldir_t);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+#include <linux/spinlock.h>
+#else
+#include <asm/spinlock.h>
+#endif
-static struct file_operations adfs_dir_operations = {
- NULL, /* lseek - default */
- adfs_dirread, /* read */
- NULL, /* write - bad */
- adfs_readdir, /* readdir */
- NULL, /* select - default */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- file_fsync, /* fsync */
- NULL, /* fasync */
-};
+#include "adfs.h"
/*
- * directories can handle most operations...
+ * For future. This should probably be per-directory.
*/
-struct inode_operations adfs_dir_inode_operations = {
- &adfs_dir_operations, /* default directory file-ops */
- NULL, /* create */
- adfs_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* read link */
- NULL, /* follow link */
- NULL, /* get_block */
- NULL, /* read page */
- NULL, /* write page */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
-};
+static rwlock_t adfs_dir_lock;
-unsigned int adfs_val (unsigned char *p, int len)
+static int
+adfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- unsigned int val = 0;
-
- switch (len) {
- case 4:
- val |= p[3] << 24;
- case 3:
- val |= p[2] << 16;
- case 2:
- val |= p[1] << 8;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct super_block *sb = filp->f_dentry->d_sb;
+ struct adfs_dir_ops *ops = sb->u.adfs_sb.s_dir;
+ struct object_info obj;
+ struct adfs_dir dir;
+ int ret;
+
+ ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
+ if (ret)
+ goto out;
+
+ switch (filp->f_pos) {
+ case 0:
+ if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0)
+ goto free_out;
+ filp->f_pos += 1;
+
+ case 1:
+ if (filldir(dirent, "..", 2, 1, dir.parent_id) < 0)
+ goto free_out;
+ filp->f_pos += 1;
+
default:
- val |= p[0];
+ break;
}
- return val;
-}
-
-static unsigned int adfs_filetype (unsigned int load)
-{
- if ((load & 0xfff00000) != 0xfff00000)
- return (unsigned int) -1;
- return (load >> 8) & 0xfff;
-}
-static unsigned int adfs_time (unsigned int load, unsigned int exec)
-{
- unsigned int high, low;
-
- /* Check for unstamped files. */
- if ((load & 0xfff00000) != 0xfff00000)
- return 0;
+ read_lock(&adfs_dir_lock);
- high = ((load << 24) | (exec >> 8));
- low = exec & 255;
-
- /* Files dated pre 1970. */
- if (high < 0x336e996a)
- return 0;
+ ret = ops->setpos(&dir, filp->f_pos - 2);
+ if (ret)
+ goto unlock_out;
+ while (ops->getnext(&dir, &obj) == 0) {
+ if (filldir(dirent, obj.name, obj.name_len,
+ filp->f_pos, obj.file_id) < 0)
+ goto unlock_out;
+ filp->f_pos += 1;
+ }
- high -= 0x336e996a;
+unlock_out:
+ read_unlock(&adfs_dir_lock);
- /* Files dated post 2038 ish. */
- if (high > 0x31ffffff)
- return 0x7fffffff;
+free_out:
+ ops->free(&dir);
- /* 65537 = h256,l1
- * (h256 % 100) = 56 h256 / 100 = 2
- * 56 << 8 = 14336 2 * 256 = 512
- * + l1 = 14337
- * / 100 = 143
- * + 512 = 655
- */
- return (((high % 100) << 8) + low) / 100 + (high / 100 << 8);
+out:
+ return ret;
}
-int adfs_readname (char *buf, char *ptr, int maxlen)
+int
+adfs_dir_update(struct super_block *sb, struct object_info *obj)
{
- int size = 0;
- while (*ptr >= ' ' && maxlen--) {
- switch (*ptr) {
- case '/':
- *buf++ = '.';
- break;
- default:
- *buf++ = *ptr;
- break;
- }
- ptr++;
- size ++;
+ struct adfs_dir_ops *ops = sb->u.adfs_sb.s_dir;
+ struct adfs_dir dir;
+ int ret = -EINVAL;
+
+ printk(KERN_INFO "adfs_dir_update: object %06X in dir %06X\n",
+ obj->file_id, obj->parent_id);
+#if 0
+ if (!ops->update) {
+ ret = -EINVAL;
+ goto out;
}
- *buf = '\0';
- return size;
-}
-int adfs_dir_read_parent (struct inode *inode, struct buffer_head **bhp)
-{
- struct super_block *sb;
- int i, size;
-
- sb = inode->i_sb;
-
- size = 2048 >> sb->s_blocksize_bits;
-
- for (i = 0; i < size; i++) {
- int block;
-
- block = adfs_parent_bmap (inode, i);
- if (block)
- bhp[i] = bread (sb->s_dev, block, sb->s_blocksize);
- else
- adfs_error (sb, "adfs_dir_read_parent",
- "directory %lu with a hole at offset %d", inode->i_ino, i);
- if (!block || !bhp[i]) {
- int j;
- for (j = i - 1; j >= 0; j--)
- brelse (bhp[j]);
- return 0;
- }
- }
- return i;
+ ret = ops->read(sb, obj->parent_id, 0, &dir);
+ if (ret)
+ goto out;
+
+ write_lock(&adfs_dir_lock);
+ ret = ops->update(&dir, obj);
+ write_unlock(&adfs_dir_lock);
+
+ ops->free(&dir);
+out:
+#endif
+ return ret;
}
-int adfs_dir_read (struct inode *inode, struct buffer_head **bhp)
+static int
+adfs_match(struct qstr *name, struct object_info *obj)
{
- struct super_block *sb;
- int i, size;
+ int i;
- if (!inode || !S_ISDIR(inode->i_mode))
+ if (name->len != obj->name_len)
return 0;
- sb = inode->i_sb;
+ for (i = 0; i < name->len; i++) {
+ char c1, c2;
- size = inode->i_size >> sb->s_blocksize_bits;
+ c1 = name->name[i];
+ c2 = obj->name[i];
- for (i = 0; i < size; i++) {
- int block;
+ if (c1 >= 'A' && c1 <= 'Z')
+ c1 += 'a' - 'A';
+ if (c2 >= 'A' && c2 <= 'Z')
+ c2 += 'a' - 'A';
- block = adfs_bmap (inode, i);
- if (block)
- bhp[i] = bread (sb->s_dev, block, sb->s_blocksize);
- else
- adfs_error (sb, "adfs_dir_read",
- "directory %lX,%lX with a hole at offset %d",
- inode->i_ino, inode->u.adfs_i.file_id, i);
- if (!block || !bhp[i]) {
- int j;
- for (j = i - 1; j >= 0; j--)
- brelse (bhp[j]);
+ if (c1 != c2)
return 0;
- }
}
- return i;
+ return 1;
}
-int adfs_dir_check (struct inode *inode, struct buffer_head **bhp, int buffers, union adfs_dirtail *dtp)
+static int
+adfs_dir_lookup_byname(struct inode *inode, struct qstr *name, struct object_info *obj)
{
- struct adfs_dirheader dh;
- union adfs_dirtail dt;
-
- memcpy (&dh, bhp[0]->b_data, sizeof (dh));
- memcpy (&dt, bhp[3]->b_data + 471, sizeof(dt));
-
- if (memcmp (&dh.startmasseq, &dt.new.endmasseq, 5) ||
- (memcmp (&dh.startname, "Nick", 4) &&
- memcmp (&dh.startname, "Hugo", 4))) {
- adfs_error (inode->i_sb, "adfs_check_dir",
- "corrupted directory inode %lX,%lX",
- inode->i_ino, inode->u.adfs_i.file_id);
- return 1;
+ struct super_block *sb = inode->i_sb;
+ struct adfs_dir_ops *ops = sb->u.adfs_sb.s_dir;
+ struct adfs_dir dir;
+ int ret;
+
+ ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
+ if (ret)
+ goto out;
+
+ if (inode->u.adfs_i.parent_id != dir.parent_id) {
+ adfs_error(sb, "parent directory changed under me! (%lx but got %lx)\n",
+ inode->u.adfs_i.parent_id, dir.parent_id);
+ ret = -EIO;
+ goto free_out;
}
- if (dtp)
- *dtp = dt;
- return 0;
-}
-
-void adfs_dir_free (struct buffer_head **bhp, int buffers)
-{
- int i;
-
- for (i = buffers - 1; i >= 0; i--)
- brelse (bhp[i]);
-}
-
-/* convert a disk-based directory entry to a Linux ADFS directory entry */
-static inline void
-adfs_dirent_to_idirent(struct adfs_idir_entry *ide, struct adfs_direntry *de)
-{
- ide->name_len = adfs_readname(ide->name, de->dirobname, ADFS_NAME_LEN);
- ide->file_id = adfs_val(de->dirinddiscadd, 3);
- ide->size = adfs_val(de->dirlen, 4);
- ide->mode = de->newdiratts;
- ide->mtime = adfs_time(adfs_val(de->dirload, 4), adfs_val(de->direxec, 4));
- ide->filetype = adfs_filetype(adfs_val(de->dirload, 4));
-}
-int adfs_dir_get (struct super_block *sb, struct buffer_head **bhp,
- int buffers, int pos, unsigned long parent_object_id,
- struct adfs_idir_entry *ide)
-{
- struct adfs_direntry de;
- int thissize, buffer, offset;
+ obj->parent_id = inode->i_ino;
- offset = pos & (sb->s_blocksize - 1);
- buffer = pos >> sb->s_blocksize_bits;
+ /*
+ * '.' is handled by reserved_lookup() in fs/namei.c
+ */
+ if (name->len == 2 && name->name[0] == '.' && name->name[1] == '.') {
+ /*
+ * Currently unable to fill in the rest of 'obj',
+ * but this is better than nothing. We need to
+ * ascend one level to find it's parent.
+ */
+ obj->name_len = 0;
+ obj->file_id = obj->parent_id;
+ goto free_out;
+ }
- if (buffer > buffers)
- return 0;
+ read_lock(&adfs_dir_lock);
- thissize = sb->s_blocksize - offset;
- if (thissize > 26)
- thissize = 26;
+ ret = ops->setpos(&dir, 0);
+ if (ret)
+ goto unlock_out;
- memcpy (&de, bhp[buffer]->b_data + offset, thissize);
- if (thissize != 26)
- memcpy (((char *)&de) + thissize, bhp[buffer + 1]->b_data, 26 - thissize);
+ ret = -ENOENT;
+ while (ops->getnext(&dir, obj) == 0) {
+ if (adfs_match(name, obj)) {
+ ret = 0;
+ break;
+ }
+ }
- if (!de.dirobname[0])
- return 0;
+unlock_out:
+ read_unlock(&adfs_dir_lock);
- ide->inode_no = adfs_inode_generate (parent_object_id, pos);
- adfs_dirent_to_idirent(ide, &de);
- return 1;
+free_out:
+ ops->free(&dir);
+out:
+ return ret;
}
-int adfs_dir_find_entry (struct super_block *sb, struct buffer_head **bhp,
- int buffers, unsigned int pos,
- struct adfs_idir_entry *ide)
+static ssize_t
+adfs_dir_no_read(struct file *filp, char *buf, size_t siz, loff_t *ppos)
{
- struct adfs_direntry de;
- int offset, buffer, thissize;
+ return -EISDIR;
+}
- offset = pos & (sb->s_blocksize - 1);
- buffer = pos >> sb->s_blocksize_bits;
+static struct file_operations adfs_dir_operations = {
+ read: adfs_dir_no_read,
+ readdir: adfs_readdir,
+ fsync: file_fsync,
+};
+
+static int
+adfs_hash(struct dentry *parent, struct qstr *qstr)
+{
+ const unsigned int name_len = parent->d_sb->u.adfs_sb.s_namelen;
+ const unsigned char *name;
+ unsigned long hash;
+ int i;
- if (buffer > buffers)
+ if (qstr->len < name_len)
return 0;
- thissize = sb->s_blocksize - offset;
- if (thissize > 26)
- thissize = 26;
+ /*
+ * Truncate the name in place, avoids
+ * having to define a compare function.
+ */
+ qstr->len = i = name_len;
+ name = qstr->name;
+ hash = init_name_hash();
+ while (i--) {
+ char c;
- memcpy (&de, bhp[buffer]->b_data + offset, thissize);
- if (thissize != 26)
- memcpy (((char *)&de) + thissize, bhp[buffer + 1]->b_data, 26 - thissize);
+ c = *name++;
+ if (c >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
- if (!de.dirobname[0])
- return 0;
+ hash = partial_name_hash(c, hash);
+ }
+ qstr->hash = end_name_hash(hash);
- adfs_dirent_to_idirent(ide, &de);
- return 1;
-}
+ return 0;
+}
-static int adfs_readdir (struct file *filp, void *dirent, filldir_t filldir)
+/*
+ * Compare two names, taking note of the name length
+ * requirements of the underlying filesystem.
+ */
+static int
+adfs_compare(struct dentry *parent, struct qstr *entry, struct qstr *name)
{
- struct inode *inode = filp->f_dentry->d_inode;
- struct super_block *sb;
- struct buffer_head *bh[4];
- union adfs_dirtail dt;
- unsigned long parent_object_id, dir_object_id;
- int buffers, pos;
-
- sb = inode->i_sb;
+ int i;
- if (filp->f_pos > ADFS_NUM_DIR_ENTRIES + 2)
- return -ENOENT;
+ if (entry->len != name->len)
+ return 1;
- if (!(buffers = adfs_dir_read (inode, bh))) {
- adfs_error (sb, "adfs_readdir", "unable to read directory");
- return -EINVAL;
- }
+ for (i = 0; i < name->len; i++) {
+ char a, b;
- if (adfs_dir_check (inode, bh, buffers, &dt)) {
- adfs_dir_free (bh, buffers);
- return -ENOENT;
- }
+ a = entry->name[i];
+ b = name->name[i];
- parent_object_id = adfs_val (dt.new.dirparent, 3);
- dir_object_id = adfs_inode_objid (inode);
+ if (a >= 'A' && a <= 'Z')
+ a += 'a' - 'A';
+ if (b >= 'A' && b <= 'Z')
+ b += 'a' - 'A';
- if (filp->f_pos < 2) {
- if (filp->f_pos < 1) {
- if (filldir (dirent, ".", 1, 0, inode->i_ino) < 0)
- return 0;
- filp->f_pos ++;
- }
- if (filldir (dirent, "..", 2, 1,
- adfs_inode_generate (parent_object_id, 0)) < 0)
- return 0;
- filp->f_pos ++;
+ if (a != b)
+ return 1;
}
+ return 0;
+}
- pos = 5 + (filp->f_pos - 2) * 26;
- while (filp->f_pos < 79) {
- struct adfs_idir_entry ide;
-
- if (!adfs_dir_get (sb, bh, buffers, pos, dir_object_id, &ide))
- break;
+struct dentry_operations adfs_dentry_operations = {
+ NULL, /* revalidate */
+ adfs_hash,
+ adfs_compare,
+ NULL, /* delete = called by dput */
+ NULL, /* release - called by d_free */
+ NULL /* iput - called by dentry_iput */
+};
- if (filldir (dirent, ide.name, ide.name_len, filp->f_pos, ide.inode_no) < 0)
- return 0;
- filp->f_pos ++;
- pos += 26;
+struct dentry *adfs_lookup(struct inode *dir, struct dentry *dentry)
+{
+ struct inode *inode = NULL;
+ struct object_info obj;
+ int error;
+
+ dentry->d_op = &adfs_dentry_operations;
+ error = adfs_dir_lookup_byname(dir, &dentry->d_name, &obj);
+ if (error == 0) {
+ error = -EACCES;
+ /*
+ * This only returns NULL if get_empty_inode
+ * fails.
+ */
+ inode = adfs_iget(dir->i_sb, &obj);
+ if (inode)
+ error = 0;
}
- adfs_dir_free (bh, buffers);
- return 0;
+ d_add(dentry, inode);
+ return ERR_PTR(error);
}
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations adfs_dir_inode_operations = {
+ &adfs_dir_operations, /* default directory file-ops */
+ NULL, /* create */
+ adfs_lookup, /* lookup */
+};
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
new file mode 100644
index 000000000..cec45c098
--- /dev/null
+++ b/fs/adfs/dir_f.c
@@ -0,0 +1,479 @@
+/*
+ * linux/fs/adfs/dir_f.c
+ *
+ * Copyright (C) 1997-1999 Russell King
+ *
+ * E and F format directory handling
+ */
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/adfs_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+#include <linux/spinlock.h>
+#else
+#include <asm/spinlock.h>
+#endif
+
+#include "adfs.h"
+#include "dir_f.h"
+
+static void adfs_f_free(struct adfs_dir *dir);
+
+/*
+ * Read an (unaligned) value of length 1..4 bytes
+ */
+static inline unsigned int adfs_readval(unsigned char *p, int len)
+{
+ unsigned int val = 0;
+
+ switch (len) {
+ case 4: val |= p[3] << 24;
+ case 3: val |= p[2] << 16;
+ case 2: val |= p[1] << 8;
+ default: val |= p[0];
+ }
+ return val;
+}
+
+static inline void adfs_writeval(unsigned char *p, int len, unsigned int val)
+{
+ switch (len) {
+ case 4: p[3] = val >> 24;
+ case 3: p[2] = val >> 16;
+ case 2: p[1] = val >> 8;
+ default: p[0] = val;
+ }
+}
+
+static inline int adfs_readname(char *buf, char *ptr, int maxlen)
+{
+ char *old_buf = buf;
+
+ while (*ptr >= ' ' && maxlen--) {
+ if (*ptr == '/')
+ *buf++ = '.';
+ else
+ *buf++ = *ptr;
+ ptr++;
+ }
+ *buf = '\0';
+
+ return buf - old_buf;
+}
+
+static inline void adfs_writename(char *to, char *from, int maxlen)
+{
+ int i;
+
+ for (i = 0; i < maxlen; i++) {
+ if (from[i] == '\0')
+ break;
+ if (from[i] == '.')
+ to[i] = '/';
+ else
+ to[i] = from[i];
+ }
+
+ for (; i < maxlen; i++)
+ to[i] = '\0';
+}
+
+#define ror13(v) ((v >> 13) | (v << 19))
+
+#define dir_u8(idx) \
+ ({ int _buf = idx >> blocksize_bits; \
+ int _off = idx - (_buf << blocksize_bits);\
+ *(u8 *)(bh[_buf]->b_data + _off); \
+ })
+
+#define dir_u32(idx) \
+ ({ int _buf = idx >> blocksize_bits; \
+ int _off = idx - (_buf << blocksize_bits);\
+ *(u32 *)(bh[_buf]->b_data + _off); \
+ })
+
+#define bufoff(_bh,_idx) \
+ ({ int _buf = _idx >> blocksize_bits; \
+ int _off = _idx - (_buf << blocksize_bits);\
+ (u8 *)(_bh[_buf]->b_data + _off); \
+ })
+
+/*
+ * There are some algorithms that are nice in
+ * assembler, but a bitch in C... This is one
+ * of them.
+ */
+static u8
+adfs_dir_checkbyte(const struct adfs_dir *dir)
+{
+ struct buffer_head * const *bh = dir->bh;
+ const int blocksize_bits = dir->sb->s_blocksize_bits;
+ union { u32 *ptr32; u8 *ptr8; } ptr, end;
+ u32 dircheck = 0;
+ int last = 5 - 26;
+ int i = 0;
+
+ /*
+ * Accumulate each word up to the last whole
+ * word of the last directory entry. This
+ * can spread across several buffer heads.
+ */
+ do {
+ last += 26;
+ do {
+ dircheck = cpu_to_le32(dir_u32(i)) ^ ror13(dircheck);
+
+ i += sizeof(u32);
+ } while (i < (last & ~3));
+ } while (dir_u8(last) != 0);
+
+ /*
+ * Accumulate the last few bytes. These
+ * bytes will be within the same bh.
+ */
+ if (i != last) {
+ ptr.ptr8 = bufoff(bh, i);
+ end.ptr8 = ptr.ptr8 + last - i;
+
+ do
+ dircheck = *ptr.ptr8++ ^ ror13(dircheck);
+ while (ptr.ptr8 < end.ptr8);
+ }
+
+ /*
+ * The directory tail is in the final bh
+ * Note that contary to the RISC OS PRMs,
+ * the first few bytes are NOT included
+ * in the check. All bytes are in the
+ * same bh.
+ */
+ ptr.ptr8 = bufoff(bh, 2008);
+ end.ptr8 = ptr.ptr8 + 36;
+
+ do {
+ unsigned int v = *ptr.ptr32++;
+ dircheck = cpu_to_le32(v) ^ ror13(dircheck);
+ } while (ptr.ptr32 < end.ptr32);
+
+ return (dircheck ^ (dircheck >> 8) ^ (dircheck >> 16) ^ (dircheck >> 24)) & 0xff;
+}
+
+/*
+ * Read and check that a directory is valid
+ */
+int
+adfs_dir_read(struct super_block *sb, unsigned long object_id,
+ unsigned int size, struct adfs_dir *dir)
+{
+ const unsigned int blocksize_bits = sb->s_blocksize_bits;
+ int blk = 0;
+
+ /*
+ * Directories which are not a multiple of 2048 bytes
+ * are considered bad v2 [3.6]
+ */
+ if (size & 2047)
+ goto bad_dir;
+
+ size >>= blocksize_bits;
+
+ dir->nr_buffers = 0;
+ dir->sb = sb;
+
+ for (blk = 0; blk < size; blk++) {
+ int phys;
+
+ phys = __adfs_block_map(sb, object_id, blk);
+ if (!phys) {
+ adfs_error(sb, "dir object %lX has a hole at offset %d",
+ object_id, blk);
+ goto release_buffers;
+ }
+
+ dir->bh[blk] = bread(sb->s_dev, phys, sb->s_blocksize);
+ if (!dir->bh[blk])
+ goto release_buffers;
+ }
+
+ memcpy(&dir->dirhead, bufoff(dir->bh, 0), sizeof(dir->dirhead));
+ memcpy(&dir->dirtail, bufoff(dir->bh, 2007), sizeof(dir->dirtail));
+
+ if (dir->dirhead.startmasseq != dir->dirtail.new.endmasseq ||
+ memcmp(&dir->dirhead.startname, &dir->dirtail.new.endname, 4))
+ goto bad_dir;
+
+ if (memcmp(&dir->dirhead.startname, "Nick", 4) &&
+ memcmp(&dir->dirhead.startname, "Hugo", 4))
+ goto bad_dir;
+
+ if (adfs_dir_checkbyte(dir) != dir->dirtail.new.dircheckbyte)
+ goto bad_dir;
+
+ dir->nr_buffers = blk;
+
+ return 0;
+
+bad_dir:
+ adfs_error(sb, "corrupted directory fragment %lX",
+ object_id);
+release_buffers:
+ for (blk -= 1; blk >= 0; blk -= 1)
+ brelse(dir->bh[blk]);
+
+ dir->sb = NULL;
+
+ return -EIO;
+}
+
+/*
+ * convert a disk-based directory entry to a Linux ADFS directory entry
+ */
+static inline void
+adfs_dir2obj(struct object_info *obj, struct adfs_direntry *de)
+{
+ obj->name_len = adfs_readname(obj->name, de->dirobname, ADFS_F_NAME_LEN);
+ obj->file_id = adfs_readval(de->dirinddiscadd, 3);
+ obj->loadaddr = adfs_readval(de->dirload, 4);
+ obj->execaddr = adfs_readval(de->direxec, 4);
+ obj->size = adfs_readval(de->dirlen, 4);
+ obj->attr = de->newdiratts;
+}
+
+/*
+ * convert a Linux ADFS directory entry to a disk-based directory entry
+ */
+static inline void
+adfs_obj2dir(struct adfs_direntry *de, struct object_info *obj)
+{
+ adfs_writeval(de->dirinddiscadd, 3, obj->file_id);
+ adfs_writeval(de->dirload, 4, obj->loadaddr);
+ adfs_writeval(de->direxec, 4, obj->execaddr);
+ adfs_writeval(de->dirlen, 4, obj->size);
+ de->newdiratts = obj->attr;
+}
+
+/*
+ * get a directory entry. Note that the caller is responsible
+ * for holding the relevent locks.
+ */
+int
+__adfs_dir_get(struct adfs_dir *dir, int pos, struct object_info *obj)
+{
+ struct super_block *sb = dir->sb;
+ struct adfs_direntry de;
+ int thissize, buffer, offset;
+
+ buffer = pos >> sb->s_blocksize_bits;
+
+ if (buffer > dir->nr_buffers)
+ return -EINVAL;
+
+ offset = pos & (sb->s_blocksize - 1);
+ thissize = sb->s_blocksize - offset;
+ if (thissize > 26)
+ thissize = 26;
+
+ memcpy(&de, dir->bh[buffer]->b_data + offset, thissize);
+ if (thissize != 26)
+ memcpy(((char *)&de) + thissize, dir->bh[buffer + 1]->b_data,
+ 26 - thissize);
+
+ if (!de.dirobname[0])
+ return -ENOENT;
+
+ adfs_dir2obj(obj, &de);
+
+ return 0;
+}
+
+int
+__adfs_dir_put(struct adfs_dir *dir, int pos, struct object_info *obj)
+{
+ struct super_block *sb = dir->sb;
+ struct adfs_direntry de;
+ int thissize, buffer, offset;
+
+ buffer = pos >> sb->s_blocksize_bits;
+
+ if (buffer > dir->nr_buffers)
+ return -EINVAL;
+
+ offset = pos & (sb->s_blocksize - 1);
+ thissize = sb->s_blocksize - offset;
+ if (thissize > 26)
+ thissize = 26;
+
+ /*
+ * Get the entry in total
+ */
+ memcpy(&de, dir->bh[buffer]->b_data + offset, thissize);
+ if (thissize != 26)
+ memcpy(((char *)&de) + thissize, dir->bh[buffer + 1]->b_data,
+ 26 - thissize);
+
+ /*
+ * update it
+ */
+ adfs_obj2dir(&de, obj);
+
+ /*
+ * Put the new entry back
+ */
+ memcpy(dir->bh[buffer]->b_data + offset, &de, thissize);
+ if (thissize != 26)
+ memcpy(dir->bh[buffer + 1]->b_data, ((char *)&de) + thissize,
+ 26 - thissize);
+
+ return 0;
+}
+
+/*
+ * the caller is responsible for holding the necessary
+ * locks.
+ */
+static int
+adfs_dir_find_entry(struct adfs_dir *dir, unsigned long object_id)
+{
+ int pos, ret;
+
+ ret = -ENOENT;
+
+ for (pos = 5; pos < ADFS_NUM_DIR_ENTRIES * 26 + 5; pos += 26) {
+ struct object_info obj;
+
+ if (!__adfs_dir_get(dir, pos, &obj))
+ break;
+
+ if (obj.file_id == object_id) {
+ ret = pos;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int
+adfs_f_read(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir)
+{
+ int ret;
+
+ if (sz != ADFS_NEWDIR_SIZE)
+ return -EIO;
+
+ ret = adfs_dir_read(sb, id, sz, dir);
+ if (ret)
+ adfs_error(sb, "unable to read directory");
+ else
+ dir->parent_id = adfs_readval(dir->dirtail.new.dirparent, 3);
+
+ return ret;
+}
+
+static int
+adfs_f_setpos(struct adfs_dir *dir, unsigned int fpos)
+{
+ if (fpos >= ADFS_NUM_DIR_ENTRIES)
+ return -ENOENT;
+
+ dir->pos = 5 + fpos * 26;
+ return 0;
+}
+
+static int
+adfs_f_getnext(struct adfs_dir *dir, struct object_info *obj)
+{
+ unsigned int ret;
+
+ ret = __adfs_dir_get(dir, dir->pos, obj);
+ if (ret == 0)
+ dir->pos += 26;
+
+ return ret;
+}
+
+static int
+adfs_f_update(struct adfs_dir *dir, struct object_info *obj)
+{
+ struct super_block *sb = dir->sb;
+ int ret, i;
+
+ ret = adfs_dir_find_entry(dir, obj->file_id);
+ if (ret < 0) {
+ adfs_error(dir->sb, "unable to locate entry to update");
+ goto out;
+ }
+
+ __adfs_dir_put(dir, ret, obj);
+
+ /*
+ * Increment directory sequence number
+ */
+ dir->bh[0]->b_data[0] += 1;
+ dir->bh[dir->nr_buffers - 1]->b_data[sb->s_blocksize - 6] += 1;
+
+ ret = adfs_dir_checkbyte(dir);
+ /*
+ * Update directory check byte
+ */
+ dir->bh[dir->nr_buffers - 1]->b_data[sb->s_blocksize - 1] = ret;
+
+#if 1
+ {
+ const unsigned int blocksize_bits = sb->s_blocksize_bits;
+
+ memcpy(&dir->dirhead, bufoff(dir->bh, 0), sizeof(dir->dirhead));
+ memcpy(&dir->dirtail, bufoff(dir->bh, 2007), sizeof(dir->dirtail));
+
+ if (dir->dirhead.startmasseq != dir->dirtail.new.endmasseq ||
+ memcmp(&dir->dirhead.startname, &dir->dirtail.new.endname, 4))
+ goto bad_dir;
+
+ if (memcmp(&dir->dirhead.startname, "Nick", 4) &&
+ memcmp(&dir->dirhead.startname, "Hugo", 4))
+ goto bad_dir;
+
+ if (adfs_dir_checkbyte(dir) != dir->dirtail.new.dircheckbyte)
+ goto bad_dir;
+ }
+#endif
+ for (i = dir->nr_buffers - 1; i >= 0; i--)
+ mark_buffer_dirty(dir->bh[i], 1);
+
+ ret = 0;
+out:
+ return ret;
+#if 1
+bad_dir:
+ adfs_error(dir->sb, "whoops! I broke a directory!");
+ return -EIO;
+#endif
+}
+
+static void
+adfs_f_free(struct adfs_dir *dir)
+{
+ int i;
+
+ for (i = dir->nr_buffers - 1; i >= 0; i--) {
+ brelse(dir->bh[i]);
+ dir->bh[i] = NULL;
+ }
+
+ dir->nr_buffers = 0;
+ dir->sb = NULL;
+}
+
+struct adfs_dir_ops adfs_f_dir_ops = {
+ adfs_f_read,
+ adfs_f_setpos,
+ adfs_f_getnext,
+ adfs_f_update,
+ NULL,
+ NULL,
+ adfs_f_free
+};
diff --git a/fs/adfs/dir_f.h b/fs/adfs/dir_f.h
new file mode 100644
index 000000000..8df158739
--- /dev/null
+++ b/fs/adfs/dir_f.h
@@ -0,0 +1,61 @@
+/*
+ * linux/fs/adfs/dir_f.h
+ *
+ * Copyright (C) 1999 Russell King
+ *
+ * Structures of directories on the F format disk
+ */
+#ifndef ADFS_DIR_F_H
+#define ADFS_DIR_F_H
+
+/*
+ * Directory header
+ */
+struct adfs_dirheader {
+ unsigned char startmasseq;
+ unsigned char startname[4];
+};
+
+#define ADFS_NEWDIR_SIZE 2048
+#define ADFS_NUM_DIR_ENTRIES 77
+
+/*
+ * Directory entries
+ */
+struct adfs_direntry {
+#define ADFS_F_NAME_LEN 10
+ char dirobname[ADFS_F_NAME_LEN];
+ __u8 dirload[4];
+ __u8 direxec[4];
+ __u8 dirlen[4];
+ __u8 dirinddiscadd[3];
+ __u8 newdiratts;
+};
+
+/*
+ * Directory tail
+ */
+union adfs_dirtail {
+ struct {
+ unsigned char dirlastmask;
+ char dirname[10];
+ unsigned char dirparent[3];
+ char dirtitle[19];
+ unsigned char reserved[14];
+ unsigned char endmasseq;
+ unsigned char endname[4];
+ unsigned char dircheckbyte;
+ } old;
+ struct {
+ unsigned char dirlastmask;
+ unsigned char reserved[2];
+ unsigned char dirparent[3];
+ char dirtitle[19];
+ char dirname[10];
+ unsigned char endmasseq;
+ unsigned char endname[4];
+ unsigned char dircheckbyte;
+ } new;
+};
+
+#endif
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
new file mode 100644
index 000000000..afb770d0d
--- /dev/null
+++ b/fs/adfs/dir_fplus.c
@@ -0,0 +1,182 @@
+/*
+ * linux/fs/adfs/dir_fplus.c
+ *
+ * Copyright (C) 1997-1999 Russell King
+ */
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/adfs_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+#include <linux/spinlock.h>
+#else
+#include <asm/spinlock.h>
+#endif
+
+#include "adfs.h"
+#include "dir_fplus.h"
+
+static int
+adfs_fplus_read(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir)
+{
+ struct adfs_bigdirheader *h;
+ struct adfs_bigdirtail *t;
+ unsigned long block;
+ unsigned int blk, size;
+ int i, ret = -EIO;
+
+ dir->nr_buffers = 0;
+
+ block = __adfs_block_map(sb, id, 0);
+ if (!block) {
+ adfs_error(sb, "dir object %X has a hole at offset 0", id);
+ goto out;
+ }
+
+ dir->bh[0] = bread(sb->s_dev, block, sb->s_blocksize);
+ if (!dir->bh[0])
+ goto out;
+ dir->nr_buffers += 1;
+
+ h = (struct adfs_bigdirheader *)dir->bh[0]->b_data;
+ size = le32_to_cpu(h->bigdirsize);
+ if (size != sz) {
+ printk(KERN_WARNING "adfs: adfs_fplus_read: directory header size\n"
+ " does not match directory size\n");
+ }
+
+ if (h->bigdirversion[0] != 0 || h->bigdirversion[1] != 0 ||
+ h->bigdirversion[2] != 0 || size & 2047 ||
+ h->bigdirstartname != cpu_to_le32(BIGDIRSTARTNAME))
+ goto out;
+
+ size >>= sb->s_blocksize_bits;
+ for (blk = 1; blk < size; blk++) {
+ block = __adfs_block_map(sb, id, blk);
+ if (!block) {
+ adfs_error(sb, "dir object %X has a hole at offset %d", id, blk);
+ goto out;
+ }
+
+ dir->bh[blk] = bread(sb->s_dev, block, sb->s_blocksize);
+ if (!dir->bh[blk])
+ goto out;
+ dir->nr_buffers = blk;
+ }
+
+ t = (struct adfs_bigdirtail *)(dir->bh[size - 1]->b_data + (sb->s_blocksize - 8));
+
+ if (t->bigdirendname != cpu_to_le32(BIGDIRENDNAME) ||
+ t->bigdirendmasseq != h->startmasseq ||
+ t->reserved[0] != 0 || t->reserved[1] != 0)
+ goto out;
+
+ dir->parent_id = le32_to_cpu(h->bigdirparent);
+ dir->sb = sb;
+ return 0;
+out:
+ for (i = 0; i < dir->nr_buffers; i++)
+ brelse(dir->bh[i]);
+ dir->sb = NULL;
+ return ret;
+}
+
+static int
+adfs_fplus_setpos(struct adfs_dir *dir, unsigned int fpos)
+{
+ struct adfs_bigdirheader *h = (struct adfs_bigdirheader *)dir->bh[0]->b_data;
+ int ret = -ENOENT;
+
+ if (fpos <= le32_to_cpu(h->bigdirentries)) {
+ dir->pos = fpos;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static void
+dir_memcpy(struct adfs_dir *dir, unsigned int offset, void *to, int len)
+{
+ struct super_block *sb = dir->sb;
+ unsigned int buffer, partial, remainder;
+
+ buffer = offset >> sb->s_blocksize_bits;
+ offset &= sb->s_blocksize - 1;
+
+ partial = sb->s_blocksize - offset;
+
+ if (partial >= len)
+ memcpy(to, dir->bh[buffer]->b_data + offset, len);
+ else {
+ char *c = (char *)to;
+
+ remainder = len - partial;
+
+ memcpy(c, dir->bh[buffer]->b_data + offset, partial);
+ memcpy(c + partial, dir->bh[buffer + 1]->b_data, remainder);
+ }
+}
+
+static int
+adfs_fplus_getnext(struct adfs_dir *dir, struct object_info *obj)
+{
+ struct adfs_bigdirheader *h = (struct adfs_bigdirheader *)dir->bh[0]->b_data;
+ struct adfs_bigdirentry bde;
+ unsigned int offset;
+ int i, ret = -ENOENT;
+
+ if (dir->pos >= le32_to_cpu(h->bigdirentries))
+ goto out;
+
+ offset = offsetof(struct adfs_bigdirheader, bigdirname);
+ offset += ((le32_to_cpu(h->bigdirnamelen) + 4) & ~3);
+ offset += dir->pos * sizeof(struct adfs_bigdirentry);
+
+ dir_memcpy(dir, offset, &bde, sizeof(struct adfs_bigdirentry));
+
+ obj->loadaddr = le32_to_cpu(bde.bigdirload);
+ obj->execaddr = le32_to_cpu(bde.bigdirexec);
+ obj->size = le32_to_cpu(bde.bigdirlen);
+ obj->file_id = le32_to_cpu(bde.bigdirindaddr);
+ obj->attr = le32_to_cpu(bde.bigdirattr);
+ obj->name_len = le32_to_cpu(bde.bigdirobnamelen);
+
+ offset = offsetof(struct adfs_bigdirheader, bigdirname);
+ offset += ((le32_to_cpu(h->bigdirnamelen) + 4) & ~3);
+ offset += le32_to_cpu(h->bigdirentries) * sizeof(struct adfs_bigdirentry);
+ offset += le32_to_cpu(bde.bigdirobnameptr);
+
+ dir_memcpy(dir, offset, obj->name, obj->name_len);
+ for (i = 0; i < obj->name_len; i++)
+ if (obj->name[i] == '/')
+ obj->name[i] = '.';
+
+ dir->pos += 1;
+ ret = 0;
+out:
+ return ret;
+}
+
+static void
+adfs_fplus_free(struct adfs_dir *dir)
+{
+ int i;
+
+ for (i = 0; i < dir->nr_buffers; i++)
+ brelse(dir->bh[i]);
+ dir->sb = NULL;
+}
+
+struct adfs_dir_ops adfs_fplus_dir_ops = {
+ adfs_fplus_read,
+ adfs_fplus_setpos,
+ adfs_fplus_getnext,
+ NULL,
+ NULL,
+ NULL,
+ adfs_fplus_free
+};
diff --git a/fs/adfs/dir_fplus.h b/fs/adfs/dir_fplus.h
new file mode 100644
index 000000000..5b3adefca
--- /dev/null
+++ b/fs/adfs/dir_fplus.h
@@ -0,0 +1,41 @@
+/*
+ * linux/fs/adfs/dir_fplus.h
+ *
+ * Copyright (C) 1999 Russell King
+ *
+ * Structures of directories on the F+ format disk
+ */
+
+#define ADFS_FPLUS_NAME_LEN 255
+
+#define BIGDIRSTARTNAME ('S' | 'B' << 8 | 'P' << 16 | 'r' << 24)
+#define BIGDIRENDNAME ('o' | 'v' << 8 | 'e' << 16 | 'n' << 24)
+
+struct adfs_bigdirheader {
+ __u8 startmasseq;
+ __u8 bigdirversion[3];
+ __u32 bigdirstartname;
+ __u32 bigdirnamelen;
+ __u32 bigdirsize;
+ __u32 bigdirentries;
+ __u32 bigdirnamesize;
+ __u32 bigdirparent;
+ char bigdirname[1];
+};
+
+struct adfs_bigdirentry {
+ __u32 bigdirload;
+ __u32 bigdirexec;
+ __u32 bigdirlen;
+ __u32 bigdirindaddr;
+ __u32 bigdirattr;
+ __u32 bigdirobnamelen;
+ __u32 bigdirobnameptr;
+};
+
+struct adfs_bigdirtail {
+ __u32 bigdirendname;
+ __u8 bigdirendmasseq;
+ __u8 reserved[2];
+ __u8 bigdircheckbyte;
+};
diff --git a/fs/adfs/file.c b/fs/adfs/file.c
index a4580426a..a2f105b06 100644
--- a/fs/adfs/file.c
+++ b/fs/adfs/file.c
@@ -1,7 +1,7 @@
/*
* linux/fs/adfs/file.c
*
- * Copyright (C) 1997 Russell King
+ * Copyright (C) 1997-1999 Russell King
* from:
*
* linux/fs/ext2/file.c
@@ -19,7 +19,7 @@
*
* adfs regular file handling primitives
*/
-
+#include <linux/version.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
@@ -27,42 +27,21 @@
#include <linux/sched.h>
#include <linux/stat.h>
+#include "adfs.h"
+
/*
* We have mostly NULLs here: the current defaults are OK for
* the adfs filesystem.
*/
static struct file_operations adfs_file_operations = {
- NULL, /* lseek - default */
- generic_file_read, /* read */
- NULL, /* write */
- NULL, /* readdir - bad */
- NULL, /* select - default */
- NULL, /* ioctl */
- generic_file_mmap, /* mmap */
- NULL, /* open - not special */
- NULL, /* flush */
- NULL, /* release */
- file_fsync, /* fsync */
- NULL, /* fasync */
+ read: generic_file_read,
+ mmap: generic_file_mmap,
+ fsync: file_fsync,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ write: generic_file_write,
+#endif
};
struct inode_operations adfs_file_inode_operations = {
- &adfs_file_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- adfs_bmap, /* get_block */
- block_read_full_page, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
+ &adfs_file_operations, /* default file operations */
};
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index b33044af3..30398d62f 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -1,9 +1,9 @@
/*
* linux/fs/adfs/inode.c
*
- * Copyright (C) 1997 Russell King
+ * Copyright (C) 1997-1999 Russell King
*/
-
+#include <linux/version.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/adfs_fs.h>
@@ -13,210 +13,367 @@
#include <linux/locks.h>
#include <linux/mm.h>
+#include "adfs.h"
+
/*
- * Old Inode numbers:
- * bit 30 - 16 FragID of parent object
- * bit 15 0 1
- * bit 14 - 0 FragID of object Offset into parent FragID
- *
- * New Inode numbers:
- * Inode = Frag ID of parent (14) + Frag Offset (8) + (index into directory + 1)(8)
+ * Lookup/Create a block at offset 'block' into 'inode'. We currently do
+ * not support creation of new blocks, so we return -EIO for this case.
*/
-#define inode_frag(ino) ((ino) >> 8)
-#define inode_idx(ino) ((ino) & 0xff)
-#define inode_dirindex(idx) (((idx) & 0xff) * 26 - 21)
-
-#define frag_id(x) (((x) >> 8) & 0x7fff)
-#define off(x) (((x) & 0xff) ? (((x) & 0xff) - 1) << sb->u.adfs_sb.s_dr->log2sharesize : 0)
-
-static inline int adfs_inode_validate_no (struct super_block *sb, unsigned int inode_no)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+int
+adfs_get_block(struct inode *inode, long block, struct buffer_head *bh, int create)
{
- unsigned long max_frag_id;
+ if (block < 0)
+ goto abort_negative;
+
+ if (!create) {
+ if (block >= inode->i_blocks)
+ goto abort_toobig;
+
+ block = __adfs_block_map(inode->i_sb, inode->i_ino, block);
+ if (block) {
+ bh->b_dev = inode->i_dev;
+ bh->b_blocknr = block;
+ bh->b_state |= (1UL << BH_Mapped);
+ }
+ return 0;
+ }
+ /* don't support allocation of blocks yet */
+ return -EIO;
- max_frag_id = sb->u.adfs_sb.s_map_size * sb->u.adfs_sb.s_ids_per_zone;
+abort_negative:
+ adfs_error(inode->i_sb, "block %d < 0", block);
+ return -EIO;
- return (inode_no & 0x800000ff) ||
- (frag_id (inode_frag (inode_no)) > max_frag_id) ||
- (frag_id (inode_frag (inode_no)) < 2);
+abort_toobig:
+ return 0;
}
-
-int adfs_inode_validate (struct inode *inode)
+static int adfs_writepage(struct dentry *dentry, struct page *page)
{
- struct super_block *sb = inode->i_sb;
+ return block_write_full_page(page,adfs_get_block);
+}
+static int adfs_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,adfs_get_block);
+}
+static int adfs_prepare_write(struct page *page, unsigned from, unsigned to)
+{
+ return cont_prepare_write(page,from,to,adfs_get_block,
+ &((struct inode*)page->mapping->host)->u.adfs_i.mmu_private);
+}
+static int _adfs_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,adfs_get_block);
+}
+struct address_space_operations adfs_aops = {
+ readpage: adfs_readpage,
+ writepage: adfs_writepage,
+ prepare_write: adfs_prepare_write,
+ commit_write: generic_commit_write,
+ bmap: _adfs_bmap
+};
+#else
+int adfs_bmap(struct inode *inode, int block)
+{
+ if (block >= inode->i_blocks)
+ return 0;
- return adfs_inode_validate_no (sb, inode->i_ino & 0xffffff00) ||
- adfs_inode_validate_no (sb, inode->u.adfs_i.file_id << 8);
+ return __adfs_block_map(inode->i_sb, inode->i_ino, block);
}
+#endif
-unsigned long adfs_inode_generate (unsigned long parent_id, int diridx)
+static inline unsigned int
+adfs_filetype(struct inode *inode)
{
- if (!parent_id)
- return -1;
+ unsigned int type;
- if (diridx)
- diridx = (diridx + 21) / 26;
+ if (inode->u.adfs_i.stamped)
+ type = (inode->u.adfs_i.loadaddr >> 8) & 0xfff;
+ else
+ type = (unsigned int) -1;
- return (parent_id << 8) | diridx;
+ return type;
}
-unsigned long adfs_inode_objid (struct inode *inode)
+/*
+ * Convert ADFS attributes and filetype to Linux permission.
+ */
+static umode_t
+adfs_atts2mode(struct super_block *sb, struct inode *inode)
{
- if (adfs_inode_validate (inode)) {
- adfs_error (inode->i_sb, "adfs_inode_objid",
- "bad inode number: %lu (%X,%X)",
- inode->i_ino, inode->i_ino, inode->u.adfs_i.file_id);
- return 0;
+ unsigned int filetype, attr = inode->u.adfs_i.attr;
+ umode_t mode, rmask;
+
+ if (attr & ADFS_NDA_DIRECTORY) {
+ mode = S_IRUGO & sb->u.adfs_sb.s_owner_mask;
+ return S_IFDIR | S_IXUGO | mode;
}
- return inode->u.adfs_i.file_id;
-}
+ filetype = adfs_filetype(inode);
-int adfs_bmap (struct inode *inode, int block)
-{
- struct super_block *sb = inode->i_sb;
- unsigned int blk;
+ switch (filetype) {
+ case 0xfc0: /* LinkFS */
+ return S_IFLNK|S_IRWXUGO;
- if (adfs_inode_validate (inode)) {
- adfs_error (sb, "adfs_bmap",
- "bad inode number: %lu (%X,%X)",
- inode->i_ino, inode->i_ino, inode->u.adfs_i.file_id);
- return 0;
- }
+ case 0xfe6: /* UnixExec */
+ rmask = S_IRUGO | S_IXUGO;
+ break;
- if (block < 0) {
- adfs_error(sb, "adfs_bmap", "block(%d) < 0", block);
- return 0;
+ default:
+ rmask = S_IRUGO;
}
- if (block > inode->i_blocks)
- return 0;
+ mode = S_IFREG;
- block += off(inode->u.adfs_i.file_id);
+ if (attr & ADFS_NDA_OWNER_READ)
+ mode |= rmask & sb->u.adfs_sb.s_owner_mask;
- if (frag_id(inode->u.adfs_i.file_id) == ADFS_ROOT_FRAG)
- blk = sb->u.adfs_sb.s_map_block + block;
- else
- blk = adfs_map_lookup (sb, frag_id(inode->u.adfs_i.file_id), block);
- return blk;
+ if (attr & ADFS_NDA_OWNER_WRITE)
+ mode |= S_IWUGO & sb->u.adfs_sb.s_owner_mask;
+
+ if (attr & ADFS_NDA_PUBLIC_READ)
+ mode |= rmask & sb->u.adfs_sb.s_other_mask;
+
+ if (attr & ADFS_NDA_PUBLIC_WRITE)
+ mode |= S_IWUGO & sb->u.adfs_sb.s_other_mask;
+ return mode;
}
-unsigned int adfs_parent_bmap (struct inode *inode, int block)
+/*
+ * Convert Linux permission to ADFS attribute. We try to do the reverse
+ * of atts2mode, but there is not a 1:1 translation.
+ */
+static int
+adfs_mode2atts(struct super_block *sb, struct inode *inode)
{
- struct super_block *sb = inode->i_sb;
- unsigned int blk, fragment;
+ umode_t mode;
+ int attr;
- if (adfs_inode_validate_no (sb, inode->i_ino & 0xffffff00)) {
- adfs_error (sb, "adfs_parent_bmap",
- "bad inode number: %lu (%X,%X)",
- inode->i_ino, inode->i_ino, inode->u.adfs_i.file_id);
- return 0;
- }
+ /* FIXME: should we be able to alter a link? */
+ if (S_ISLNK(inode->i_mode))
+ return inode->u.adfs_i.attr;
- fragment = inode_frag (inode->i_ino);
- if (frag_id (fragment) == ADFS_ROOT_FRAG)
- blk = sb->u.adfs_sb.s_map_block + off(fragment) + block;
+ if (S_ISDIR(inode->i_mode))
+ attr = ADFS_NDA_DIRECTORY;
else
- blk = adfs_map_lookup (sb, frag_id (fragment), off(fragment) + block);
- return blk;
+ attr = 0;
+
+ mode = inode->i_mode & sb->u.adfs_sb.s_owner_mask;
+ if (mode & S_IRUGO)
+ attr |= ADFS_NDA_OWNER_READ;
+ if (mode & S_IWUGO)
+ attr |= ADFS_NDA_OWNER_WRITE;
+
+ mode = inode->i_mode & sb->u.adfs_sb.s_other_mask;
+ mode &= ~sb->u.adfs_sb.s_owner_mask;
+ if (mode & S_IRUGO)
+ attr |= ADFS_NDA_PUBLIC_READ;
+ if (mode & S_IWUGO)
+ attr |= ADFS_NDA_PUBLIC_WRITE;
+
+ return attr;
}
-static int adfs_atts2mode(struct super_block *sb, unsigned char mode, unsigned int filetype)
+/*
+ * Convert an ADFS time to Unix time. ADFS has a 40-bit centi-second time
+ * referenced to 1 Jan 1900 (til 2248)
+ */
+static unsigned int
+adfs_adfs2unix_time(struct inode *inode)
{
- int omode = 0;
-
- if (filetype == 0xfc0 /* LinkFS */) {
- omode = S_IFLNK|S_IRUSR|S_IWUSR|S_IXUSR|
- S_IRGRP|S_IWGRP|S_IXGRP|
- S_IROTH|S_IWOTH|S_IXOTH;
- } else {
- if (mode & ADFS_NDA_DIRECTORY) {
- omode |= S_IRUGO & sb->u.adfs_sb.s_owner_mask;
- omode |= S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH;
- } else
- omode |= S_IFREG;
-
- if (mode & ADFS_NDA_OWNER_READ) {
- omode |= S_IRUGO & sb->u.adfs_sb.s_owner_mask;
- if (filetype == 0xfe6 /* UnixExec */)
- omode |= S_IXUGO & sb->u.adfs_sb.s_owner_mask;
- }
+ unsigned int high, low;
- if (mode & ADFS_NDA_OWNER_WRITE)
- omode |= S_IWUGO & sb->u.adfs_sb.s_owner_mask;
+ if (inode->u.adfs_i.stamped == 0)
+ return CURRENT_TIME;
- if (mode & ADFS_NDA_PUBLIC_READ) {
- omode |= S_IRUGO & sb->u.adfs_sb.s_other_mask;
- if (filetype == 0xfe6 /* UnixExec */)
- omode |= S_IXUGO & sb->u.adfs_sb.s_other_mask;
- }
+ high = inode->u.adfs_i.loadaddr << 24;
+ low = inode->u.adfs_i.execaddr;
- if (mode & ADFS_NDA_PUBLIC_WRITE)
- omode |= S_IWUGO & sb->u.adfs_sb.s_other_mask;
- }
- return omode;
+ high |= low >> 8;
+ low &= 255;
+
+ /* Files dated pre 01 Jan 1970 00:00:00. */
+ if (high < 0x336e996a)
+ return 0;
+
+ /* Files dated post 18 Jan 2038 03:14:05. */
+ if (high >= 0x656e9969)
+ return 0x7ffffffd;
+
+ /* discard 2208988800 (0x336e996a00) seconds of time */
+ high -= 0x336e996a;
+
+ /* convert 40-bit centi-seconds to 32-bit seconds */
+ return (((high % 100) << 8) + low) / 100 + (high / 100 << 8);
}
-void adfs_read_inode (struct inode *inode)
+/*
+ * Convert an Unix time to ADFS time. We only do this if the entry has a
+ * time/date stamp already.
+ */
+static void
+adfs_unix2adfs_time(struct inode *inode, unsigned int secs)
{
- struct super_block *sb;
- struct buffer_head *bh[4];
- struct adfs_idir_entry ide;
- int buffers;
-
- sb = inode->i_sb;
- inode->i_uid = sb->u.adfs_sb.s_uid;
- inode->i_gid = sb->u.adfs_sb.s_gid;
- inode->i_version = ++event;
+ unsigned int high, low;
+
+ if (inode->u.adfs_i.stamped) {
+ /* convert 32-bit seconds to 40-bit centi-seconds */
+ low = (secs & 255) * 100;
+ high = (secs / 256) * 100 + (low << 8) + 0x336e996a;
- if (adfs_inode_validate_no (sb, inode->i_ino & 0xffffff00)) {
- adfs_error (sb, "adfs_read_inode",
- "bad inode number: %lu", inode->i_ino);
- goto bad;
+ inode->u.adfs_i.loadaddr = (high >> 24) |
+ (inode->u.adfs_i.loadaddr & ~0xff);
+ inode->u.adfs_i.execaddr = (low & 255) | (high << 8);
}
+}
- if (frag_id(inode_frag (inode->i_ino)) == ADFS_ROOT_FRAG &&
- inode_idx (inode->i_ino) == 0) {
- /* root dir */
- inode->i_mode = S_IRWXUGO | S_IFDIR;
- inode->i_nlink = 2;
- inode->i_size = ADFS_NEWDIR_SIZE;
- inode->i_blksize = PAGE_SIZE;
- inode->i_blocks = inode->i_size >> sb->s_blocksize_bits;
- inode->i_mtime =
- inode->i_atime =
- inode->i_ctime = 0;
- inode->u.adfs_i.file_id = inode_frag (inode->i_ino);
- } else {
- if (!(buffers = adfs_dir_read_parent (inode, bh)))
- goto bad;
-
- if (adfs_dir_check (inode, bh, buffers, NULL)) {
- adfs_dir_free (bh, buffers);
- goto bad;
- }
+/*
+ * Fill in the inode information from the object information.
+ *
+ * Note that this is an inode-less filesystem, so we can't use the inode
+ * number to reference the metadata on the media. Instead, we use the
+ * inode number to hold the object ID, which in turn will tell us where
+ * the data is held. We also save the parent object ID, and with these
+ * two, we can locate the metadata.
+ *
+ * This does mean that we rely on an objects parent remaining the same at
+ * all times - we cannot cope with a cross-directory rename (yet).
+ */
+struct inode *
+adfs_iget(struct super_block *sb, struct object_info *obj)
+{
+ struct inode *inode;
- if (!adfs_dir_find_entry (sb, bh, buffers, inode_dirindex (inode->i_ino), &ide)) {
- adfs_dir_free (bh, buffers);
- goto bad;
- }
- adfs_dir_free (bh, buffers);
- inode->i_mode = adfs_atts2mode(sb, ide.mode, ide.filetype);
- inode->i_nlink = 2;
- inode->i_size = ide.size;
- inode->i_blksize = PAGE_SIZE;
- inode->i_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
- inode->i_mtime =
- inode->i_atime =
- inode->i_ctime = ide.mtime;
- inode->u.adfs_i.file_id = ide.file_id;
- }
+ inode = get_empty_inode();
+ if (!inode)
+ goto out;
+
+ inode->i_version = ++event;
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
+ inode->i_uid = sb->u.adfs_sb.s_uid;
+ inode->i_gid = sb->u.adfs_sb.s_gid;
+ inode->i_ino = obj->file_id;
+ inode->i_size = obj->size;
+ inode->i_nlink = 2;
+ inode->i_blksize = PAGE_SIZE;
+ inode->i_blocks = (inode->i_size + sb->s_blocksize - 1) >>
+ sb->s_blocksize_bits;
+
+ /*
+ * we need to save the parent directory ID so that
+ * write_inode can update the directory information
+ * for this file. This will need special handling
+ * for cross-directory renames.
+ */
+ inode->u.adfs_i.parent_id = obj->parent_id;
+ inode->u.adfs_i.loadaddr = obj->loadaddr;
+ inode->u.adfs_i.execaddr = obj->execaddr;
+ inode->u.adfs_i.attr = obj->attr;
+ inode->u.adfs_i.stamped = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
+
+ inode->i_mode = adfs_atts2mode(sb, inode);
+ inode->i_mtime =
+ inode->i_atime =
+ inode->i_ctime = adfs_adfs2unix_time(inode);
if (S_ISDIR(inode->i_mode))
- inode->i_op = &adfs_dir_inode_operations;
- else if (S_ISREG(inode->i_mode))
+ inode->i_op = &adfs_dir_inode_operations;
+ else if (S_ISREG(inode->i_mode)) {
inode->i_op = &adfs_file_inode_operations;
- return;
+ inode->i_mapping->a_ops = &adfs_aops;
+ inode->u.adfs_i.mmu_private = inode->i_size;
+ }
+
+ insert_inode_hash(inode);
-bad:
+out:
+ return inode;
+}
+
+/*
+ * This is no longer a valid way to obtain the metadata associated with the
+ * inode number on this filesystem. This means that this filesystem cannot
+ * be shared via NFS.
+ */
+void adfs_read_inode(struct inode *inode)
+{
+ adfs_error(inode->i_sb, "unsupported method of reading inode");
make_bad_inode(inode);
}
+
+/*
+ * Validate and convert a changed access mode/time to their ADFS equivalents.
+ * adfs_write_inode will actually write the information back to the directory
+ * later.
+ */
+int
+adfs_notify_change(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ struct super_block *sb = inode->i_sb;
+ unsigned int ia_valid = attr->ia_valid;
+ int error;
+
+ error = inode_change_ok(inode, attr);
+
+ /*
+ * we can't change the UID or GID of any file -
+ * we have a global UID/GID in the superblock
+ */
+ if ((ia_valid & ATTR_UID && attr->ia_uid != sb->u.adfs_sb.s_uid) ||
+ (ia_valid & ATTR_GID && attr->ia_gid != sb->u.adfs_sb.s_gid))
+ error = -EPERM;
+
+ if (error)
+ goto out;
+
+ if (ia_valid & ATTR_SIZE)
+ inode->i_size = attr->ia_size;
+ if (ia_valid & ATTR_MTIME) {
+ inode->i_mtime = attr->ia_mtime;
+ adfs_unix2adfs_time(inode, attr->ia_mtime);
+ }
+ /*
+ * FIXME: should we make these == to i_mtime since we don't
+ * have the ability to represent them in our filesystem?
+ */
+ if (ia_valid & ATTR_ATIME)
+ inode->i_atime = attr->ia_atime;
+ if (ia_valid & ATTR_CTIME)
+ inode->i_ctime = attr->ia_ctime;
+ if (ia_valid & ATTR_MODE) {
+ inode->u.adfs_i.attr = adfs_mode2atts(sb, inode);
+ inode->i_mode = adfs_atts2mode(sb, inode);
+ }
+
+ /*
+ * FIXME: should we be marking this inode dirty even if
+ * we don't have any metadata to write back?
+ */
+ if (ia_valid & (ATTR_SIZE | ATTR_MTIME | ATTR_MODE))
+ mark_inode_dirty(inode);
+out:
+ return error;
+}
+
+/*
+ * write an existing inode back to the directory, and therefore the disk.
+ * The adfs-specific inode data has already been updated by
+ * adfs_notify_change()
+ */
+void adfs_write_inode(struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+ struct object_info obj;
+
+ obj.file_id = inode->i_ino;
+ obj.name_len = 0;
+ obj.parent_id = inode->u.adfs_i.parent_id;
+ obj.loadaddr = inode->u.adfs_i.loadaddr;
+ obj.execaddr = inode->u.adfs_i.execaddr;
+ obj.attr = inode->u.adfs_i.attr;
+ obj.size = inode->i_size;
+
+ adfs_dir_update(sb, &obj);
+}
diff --git a/fs/adfs/map.c b/fs/adfs/map.c
index 31d560143..0fde11f5d 100644
--- a/fs/adfs/map.c
+++ b/fs/adfs/map.c
@@ -1,108 +1,302 @@
/*
* linux/fs/adfs/map.c
*
- * Copyright (C) 1997 Russell King
+ * Copyright (C) 1997-1999 Russell King
*/
-
+#include <linux/version.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/adfs_fs.h>
-static inline unsigned int
-adfs_convert_map_to_sector (const struct super_block *sb, unsigned int mapoff)
-{
- if (sb->u.adfs_sb.s_map2blk >= 0)
- mapoff <<= sb->u.adfs_sb.s_map2blk;
- else
- mapoff >>= -sb->u.adfs_sb.s_map2blk;
- return mapoff;
-}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+#include <linux/spinlock.h>
+#else
+#include <asm/spinlock.h>
+#endif
+
+#include "adfs.h"
-static inline unsigned int
-adfs_convert_sector_to_map (const struct super_block *sb, unsigned int secoff)
+/*
+ * For the future...
+ */
+static rwlock_t adfs_map_lock;
+
+/*
+ * return the map bit offset of the fragment frag_id in
+ * the zone dm.
+ * Note that the loop is optimised for best asm code -
+ * look at the output of:
+ * gcc -D__KERNEL__ -O2 -I../../include -o - -S map.c
+ */
+static int
+lookup_zone(const struct adfs_discmap *dm, const unsigned int idlen,
+ const unsigned int frag_id, unsigned int *offset)
{
- if (sb->u.adfs_sb.s_map2blk >= 0)
- secoff >>= sb->u.adfs_sb.s_map2blk;
- else
- secoff <<= -sb->u.adfs_sb.s_map2blk;
- return secoff;
+ const unsigned int mapsize = dm->dm_endbit;
+ const unsigned int idmask = (1 << idlen) - 1;
+ unsigned long *map = ((unsigned long *)dm->dm_bh->b_data) + 1;
+ unsigned int start = dm->dm_startbit;
+ unsigned int mapptr;
+
+ do {
+ unsigned long frag;
+
+ /*
+ * get fragment id
+ */
+ //asm("@ get fragment id start");
+ {
+ unsigned long v2;
+ unsigned int tmp;
+
+ tmp = start >> 5;
+
+ frag = le32_to_cpu(map[tmp]);
+ v2 = le32_to_cpu(map[tmp + 1]);
+
+ tmp = start & 31;
+
+ frag = (frag >> tmp) | (v2 << (32 - tmp));
+
+ frag &= idmask;
+ }
+ //asm("@ get fragment id end");
+
+ mapptr = start + idlen;
+
+ /*
+ * find end of fragment
+ */
+ //asm("@ find end of fragment start");
+ {
+ unsigned long v2;
+
+ while ((v2 = map[mapptr >> 5] >> (mapptr & 31)) == 0) {
+ mapptr = (mapptr & ~31) + 32;
+ if (mapptr >= mapsize)
+ goto error;
+ }
+
+ mapptr += 1 + ffz(~v2);
+ }
+ //asm("@ find end of fragment end");
+
+ if (frag == frag_id)
+ goto found;
+again:
+ start = mapptr;
+ } while (mapptr < mapsize);
+
+error:
+ return -1;
+
+found:
+ {
+ int length = mapptr - start;
+ if (*offset >= length) {
+ *offset -= length;
+ goto again;
+ }
+ }
+ return start + *offset;
}
-static int lookup_zone (struct super_block *sb, int zone, int frag_id, int *offset)
+/*
+ * Scan the free space map, for this zone, calculating the total
+ * number of map bits in each free space fragment.
+ *
+ * Note: idmask is limited to 15 bits [3.2]
+ */
+static unsigned int
+scan_free_map(struct adfs_sb_info *asb, struct adfs_discmap *dm)
{
- unsigned int mapptr, idlen, mapsize;
- unsigned long *map;
+ const unsigned int mapsize = dm->dm_endbit + 32;
+ const unsigned int idlen = asb->s_idlen;
+ const unsigned int frag_idlen = idlen <= 15 ? idlen : 15;
+ const unsigned int idmask = (1 << frag_idlen) - 1;
+ unsigned long *map = (unsigned long *)dm->dm_bh->b_data;
+ unsigned int start = 8, mapptr;
+ unsigned long frag;
+ unsigned long total = 0;
+
+ /*
+ * get fragment id
+ */
+ //asm("@ get fragment id start");
+ {
+ unsigned long v2;
+ unsigned int tmp;
+
+ tmp = start >> 5;
+
+ frag = le32_to_cpu(map[tmp]);
+ v2 = le32_to_cpu(map[tmp + 1]);
+
+ tmp = start & 31;
+
+ frag = (frag >> tmp) | (v2 << (32 - tmp));
+
+ frag &= idmask;
+ }
+ //asm("@ get fragment id end");
- map = ((unsigned long *)sb->u.adfs_sb.s_map[zone]->b_data) + 1;
- zone =
- mapptr = zone == 0 ? (ADFS_DR_SIZE << 3) : 0;
- idlen = sb->u.adfs_sb.s_idlen;
- mapsize = sb->u.adfs_sb.s_zonesize;
+ /*
+ * If the freelink is null, then no free fragments
+ * exist in this zone.
+ */
+ if (frag == 0)
+ return 0;
do {
- unsigned long v1, v2;
- unsigned int start;
+ start += frag;
- v1 = map[mapptr>>5];
- v2 = map[(mapptr>>5)+1];
+ /*
+ * get fragment id
+ */
+ //asm("@ get fragment id start");
+ {
+ unsigned long v2;
+ unsigned int tmp;
- v1 = (v1 >> (mapptr & 31)) | (v2 << (32 - (mapptr & 31)));
- start = mapptr;
- mapptr += idlen;
+ tmp = start >> 5;
+
+ frag = le32_to_cpu(map[tmp]);
+ v2 = le32_to_cpu(map[tmp + 1]);
+
+ tmp = start & 31;
+
+ frag = (frag >> tmp) | (v2 << (32 - tmp));
- v2 = map[mapptr >> 5] >> (mapptr & 31);
- if (!v2) {
- mapptr = (mapptr + 32) & ~31;
- for (; (v2 = map[mapptr >> 5]) == 0 && mapptr < mapsize; mapptr += 32);
+ frag &= idmask;
}
- for (; (v2 & 255) == 0; v2 >>= 8, mapptr += 8);
- for (; (v2 & 1) == 0; v2 >>= 1, mapptr += 1);
- mapptr += 1;
-
- if ((v1 & ((1 << idlen) - 1)) == frag_id) {
- int length = mapptr - start;
- if (*offset >= length)
- *offset -= length;
- else
- return start + *offset - zone;
+ //asm("@ get fragment id end");
+
+ mapptr = start + idlen;
+
+ /*
+ * find end of fragment
+ */
+ //asm("@ find end of fragment start");
+ {
+ unsigned long v2;
+
+ while ((v2 = map[mapptr >> 5] >> (mapptr & 31)) == 0) {
+ mapptr = (mapptr & ~31) + 32;
+ if (mapptr >= mapsize)
+ goto error;
+ }
+
+ mapptr += 1 + ffz(~v2);
}
- } while (mapptr < mapsize);
+ //asm("@ find end of fragment end");
+
+ total += mapptr - start;
+ } while (frag >= idlen + 1);
+
+ if (frag != 0)
+ printk(KERN_ERR "adfs: undersized free fragment\n");
+
+ return total;
+error:
+ printk(KERN_ERR "adfs: oversized free fragment\n");
+ return 0;
+}
+
+static int
+scan_map(struct adfs_sb_info *asb, unsigned int zone,
+ const unsigned int frag_id, unsigned int mapoff)
+{
+ const unsigned int idlen = asb->s_idlen;
+ struct adfs_discmap *dm, *dm_end;
+ int result;
+
+ dm = asb->s_map + zone;
+ zone = asb->s_map_size;
+ dm_end = asb->s_map + zone;
+
+ do {
+ result = lookup_zone(dm, idlen, frag_id, &mapoff);
+
+ if (result != -1)
+ goto found;
+
+ dm ++;
+ if (dm == dm_end)
+ dm = asb->s_map;
+ } while (--zone > 0);
+
return -1;
+found:
+ result -= dm->dm_startbit;
+ result += dm->dm_startblk;
+
+ return result;
+}
+
+/*
+ * calculate the amount of free blocks in the map.
+ *
+ * n=1
+ * total_free = E(free_in_zone_n)
+ * nzones
+ */
+unsigned int
+adfs_map_free(struct super_block *sb)
+{
+ struct adfs_sb_info *asb = &sb->u.adfs_sb;
+ struct adfs_discmap *dm;
+ unsigned int total = 0;
+ unsigned int zone;
+
+ dm = asb->s_map;
+ zone = asb->s_map_size;
+
+ do {
+ total += scan_free_map(asb, dm++);
+ } while (--zone > 0);
+
+ return signed_asl(total, asb->s_map2blk);
}
int adfs_map_lookup (struct super_block *sb, int frag_id, int offset)
{
- unsigned int start_zone, zone, max_zone, mapoff, secoff;
+ struct adfs_sb_info *asb = &sb->u.adfs_sb;
+ unsigned int zone, mapoff;
+ int result;
- zone = start_zone = frag_id / sb->u.adfs_sb.s_ids_per_zone;
- max_zone = sb->u.adfs_sb.s_map_size;
+ /*
+ * map & root fragment is special - it starts in the center of the
+ * disk. The other fragments start at zone (frag / ids_per_zone)
+ */
+ if (frag_id == ADFS_ROOT_FRAG)
+ zone = asb->s_map_size >> 1;
+ else
+ zone = frag_id / asb->s_ids_per_zone;
- if (start_zone >= max_zone) {
- adfs_error (sb, "adfs_map_lookup", "fragment %X is invalid (zone = %d, max = %d)",
- frag_id, start_zone, max_zone);
- return 0;
- }
+ if (zone >= asb->s_map_size)
+ goto bad_fragment;
/* Convert sector offset to map offset */
- mapoff = adfs_convert_sector_to_map (sb, offset);
- /* Calculate sector offset into map block */
- secoff = offset - adfs_convert_map_to_sector (sb, mapoff);
+ mapoff = signed_asl(offset, -asb->s_map2blk);
- do {
- int result = lookup_zone (sb, zone, frag_id, &mapoff);
+ read_lock(&adfs_map_lock);
+ result = scan_map(asb, zone, frag_id, mapoff);
+ read_unlock(&adfs_map_lock);
- if (result != -1) {
- result += zone ? (zone * sb->u.adfs_sb.s_zonesize) - (ADFS_DR_SIZE << 3): 0;
- return adfs_convert_map_to_sector (sb, result) + secoff;
- }
+ if (result > 0) {
+ unsigned int secoff;
- zone ++;
- if (zone >= max_zone)
- zone = 0;
+ /* Calculate sector offset into map block */
+ secoff = offset - signed_asl(mapoff, asb->s_map2blk);
+ return secoff + signed_asl(result, asb->s_map2blk);
+ }
- } while (zone != start_zone);
+ adfs_error(sb, "fragment %04X at offset %d not found in map",
+ frag_id, offset);
+ return 0;
- adfs_error (sb, "adfs_map_lookup", "fragment %X at offset %d not found in map (start zone %d)",
- frag_id, offset, start_zone);
+bad_fragment:
+ adfs_error(sb, "fragment %X is invalid (zone = %d, max = %d)",
+ frag_id, zone, asb->s_map_size);
return 0;
}
diff --git a/fs/adfs/namei.c b/fs/adfs/namei.c
deleted file mode 100644
index 4e41c0975..000000000
--- a/fs/adfs/namei.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * linux/fs/adfs/namei.c
- *
- * Copyright (C) 1997 Russell King
- */
-
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/adfs_fs.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/locks.h>
-
-/*
- * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure
- */
-static int adfs_match (int len, const char * const name, struct adfs_idir_entry *de)
-{
- int i;
-
- if (!de || len > ADFS_NAME_LEN)
- return 0;
- /*
- * "" means "." ---> so paths like "/usr/lib//libc.a" work
- */
- if (!len && de->name_len == 1 && de->name[0] == '.' &&
- de->name[1] == '\0')
- return 1;
- if (len != de->name_len)
- return 0;
-
- for (i = 0; i < len; i++)
- if ((de->name[i] ^ name[i]) & 0x5f)
- return 0;
- return 1;
-}
-
-static int adfs_find_entry (struct inode *dir, const char * const name, int namelen,
- struct adfs_idir_entry *ide)
-{
- struct super_block *sb;
- struct buffer_head *bh[4];
- union adfs_dirtail dt;
- unsigned long parent_object_id, dir_object_id;
- int buffers, pos;
-
- sb = dir->i_sb;
-
- if (adfs_inode_validate (dir)) {
- adfs_error (sb, "adfs_find_entry",
- "invalid inode number: %lu", dir->i_ino);
- return 0;
- }
-
- if (!(buffers = adfs_dir_read (dir, bh))) {
- adfs_error (sb, "adfs_find_entry", "unable to read directory");
- return 0;
- }
-
- if (adfs_dir_check (dir, bh, buffers, &dt)) {
- adfs_dir_free (bh, buffers);
- return 0;
- }
-
- parent_object_id = adfs_val (dt.new.dirparent, 3);
- dir_object_id = adfs_inode_objid (dir);
-
- if (namelen == 2 && name[0] == '.' && name[1] == '.') {
- ide->name_len = 2;
- ide->name[0] = ide->name[1] = '.';
- ide->name[2] = '\0';
- ide->inode_no = adfs_inode_generate (parent_object_id, 0);
- adfs_dir_free (bh, buffers);
- return 1;
- }
-
- pos = 5;
-
- do {
- if (!adfs_dir_get (sb, bh, buffers, pos, dir_object_id, ide))
- break;
-
- if (adfs_match (namelen, name, ide)) {
- adfs_dir_free (bh, buffers);
- return pos;
- }
- pos += 26;
- } while (1);
- adfs_dir_free (bh, buffers);
- return 0;
-}
-
-struct dentry *adfs_lookup (struct inode *dir, struct dentry *dentry)
-{
- struct inode *inode = NULL;
- struct adfs_idir_entry de;
- unsigned long ino;
-
- if (dentry->d_name.len > ADFS_NAME_LEN)
- return ERR_PTR(-ENAMETOOLONG);
-
- if (adfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de)) {
- ino = de.inode_no;
- inode = iget (dir->i_sb, ino);
-
- if (!inode)
- return ERR_PTR(-EACCES);
- }
- d_add(dentry, inode);
- return NULL;
-}
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index c8db4d2e1..7b7eb2d0e 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -1,9 +1,9 @@
/*
* linux/fs/adfs/super.c
*
- * Copyright (C) 1997 Russell King
+ * Copyright (C) 1997-1999 Russell King
*/
-
+#include <linux/version.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -21,12 +21,11 @@
#include <stdarg.h>
-static void adfs_put_super(struct super_block *sb);
-static int adfs_remount(struct super_block *sb, int *flags, char *data);
-static int adfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
-void adfs_read_inode(struct inode *inode);
+#include "adfs.h"
+#include "dir_f.h"
+#include "dir_fplus.h"
-void adfs_error(struct super_block *sb, const char *function, const char *fmt, ...)
+void __adfs_error(struct super_block *sb, const char *function, const char *fmt, ...)
{
char error_buf[128];
va_list args;
@@ -40,7 +39,74 @@ void adfs_error(struct super_block *sb, const char *function, const char *fmt, .
function ? function : "", error_buf);
}
-static unsigned char adfs_calczonecheck(struct super_block *sb, char *map)
+static int adfs_checkdiscrecord(struct adfs_discrecord *dr)
+{
+ int i;
+
+ /* sector size must be 256, 512 or 1024 bytes */
+ if (dr->log2secsize != 8 &&
+ dr->log2secsize != 9 &&
+ dr->log2secsize != 10)
+ return 1;
+
+ /* idlen must be at least log2secsize + 3 */
+ if (dr->idlen < dr->log2secsize + 3)
+ return 1;
+
+ /* we cannot have such a large disc that we
+ * are unable to represent sector offsets in
+ * 32 bits. This works out at 2.0 TB.
+ */
+ if (dr->disc_size_high >> dr->log2secsize)
+ return 1;
+
+ /*
+ * The following checks are not required for F+
+ * stage 1.
+ */
+#if 0
+ /* idlen must be smaller be no greater than 15 */
+ if (dr->idlen > 15)
+ return 1;
+
+ /* nzones must be less than 128 for the root
+ * directory to be addressable
+ */
+ if (dr->nzones >= 128 && dr->nzones_high == 0)
+ return 1;
+
+ /* root must be of the form 0x2.. */
+ if ((le32_to_cpu(dr->root) & 0xffffff00) != 0x00000200)
+ return 1;
+#else
+ /*
+ * Stage 2 F+ does not require the following check
+ */
+#if 0
+ /* idlen must be no greater than 16 v2 [1.0] */
+ if (dr->idlen > 16)
+ return 1;
+
+ /* we can't handle F+ discs yet */
+ if (dr->format_version || dr->root_size)
+ return 1;
+
+#else
+ /* idlen must be no greater than 19 v2 [1.0] */
+ if (dr->idlen > 19)
+ return 1;
+#endif
+#endif
+
+ /* reserved bytes should be zero */
+ for (i = 0; i < sizeof(dr->unused52); i++)
+ if (dr->unused52[i] != 0)
+ return 1;
+
+ return 0;
+}
+
+static unsigned char adfs_calczonecheck(struct super_block *sb, unsigned char *map)
{
unsigned int v0, v1, v2, v3;
int i;
@@ -64,46 +130,34 @@ static unsigned char adfs_calczonecheck(struct super_block *sb, char *map)
return v0 ^ v1 ^ v2 ^ v3;
}
-static int adfs_checkmap(struct super_block *sb)
+static int adfs_checkmap(struct super_block *sb, struct adfs_discmap *dm)
{
unsigned char crosscheck = 0, zonecheck = 1;
int i;
for (i = 0; i < sb->u.adfs_sb.s_map_size; i++) {
- char *map;
+ unsigned char *map;
+
+ map = dm[i].dm_bh->b_data;
- map = sb->u.adfs_sb.s_map[i]->b_data;
if (adfs_calczonecheck(sb, map) != map[0]) {
- adfs_error(sb, "adfs_checkmap", "zone %d fails zonecheck", i);
+ adfs_error(sb, "zone %d fails zonecheck", i);
zonecheck = 0;
}
crosscheck ^= map[3];
}
if (crosscheck != 0xff)
- adfs_error(sb, "adfs_checkmap", "crosscheck != 0xff");
+ adfs_error(sb, "crosscheck != 0xff");
return crosscheck == 0xff && zonecheck;
}
-static struct super_operations adfs_sops = {
- adfs_read_inode,
- NULL,
- NULL,
- NULL,
- NULL,
- adfs_put_super,
- NULL,
- adfs_statfs,
- adfs_remount
-};
-
static void adfs_put_super(struct super_block *sb)
{
int i;
for (i = 0; i < sb->u.adfs_sb.s_map_size; i++)
- brelse(sb->u.adfs_sb.s_map[i]);
+ brelse(sb->u.adfs_sb.s_map[i].dm_bh);
kfree(sb->u.adfs_sb.s_map);
- brelse(sb->u.adfs_sb.s_sbh);
MOD_DEC_USE_COUNT;
}
@@ -159,13 +213,107 @@ static int adfs_remount(struct super_block *sb, int *flags, char *data)
return parse_options(sb, data);
}
+static int adfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+{
+ struct adfs_sb_info *asb = &sb->u.adfs_sb;
+ struct statfs tmp;
+
+ tmp.f_type = ADFS_SUPER_MAGIC;
+ tmp.f_namelen = asb->s_namelen;
+ tmp.f_bsize = sb->s_blocksize;
+ tmp.f_blocks = asb->s_size;
+ tmp.f_files = asb->s_ids_per_zone * asb->s_map_size;
+ tmp.f_bavail =
+ tmp.f_bfree = adfs_map_free(sb);
+ tmp.f_ffree = tmp.f_bfree * tmp.f_files / tmp.f_blocks;
+
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+}
+
+static struct super_operations adfs_sops = {
+ adfs_read_inode, /* read_inode */
+ adfs_write_inode, /* write_inode */
+ NULL, /* put_inode */
+ NULL, /* delete_inode */
+ adfs_notify_change, /* notify_change */
+ adfs_put_super, /* put_super */
+ NULL, /* write_super */
+ adfs_statfs, /* statfs */
+ adfs_remount, /* remount_fs */
+ NULL, /* clear_inode */
+ NULL /* umount_begin */
+};
+
+static struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_discrecord *dr)
+{
+ struct adfs_discmap *dm;
+ unsigned int map_addr, zone_size, nzones;
+ int i, zone;
+
+ nzones = sb->u.adfs_sb.s_map_size;
+ zone_size = (8 << dr->log2secsize) - le16_to_cpu(dr->zone_spare);
+ map_addr = (nzones >> 1) * zone_size -
+ ((nzones > 1) ? ADFS_DR_SIZE_BITS : 0);
+ map_addr = signed_asl(map_addr, sb->u.adfs_sb.s_map2blk);
+
+ sb->u.adfs_sb.s_ids_per_zone = zone_size / (sb->u.adfs_sb.s_idlen + 1);
+
+ dm = kmalloc(nzones * sizeof(*dm), GFP_KERNEL);
+ if (dm == NULL) {
+ adfs_error(sb, "not enough memory");
+ return NULL;
+ }
+
+ for (zone = 0; zone < nzones; zone++, map_addr++) {
+ dm[zone].dm_startbit = 0;
+ dm[zone].dm_endbit = zone_size;
+ dm[zone].dm_startblk = zone * zone_size - ADFS_DR_SIZE_BITS;
+ dm[zone].dm_bh = bread(sb->s_dev, map_addr, sb->s_blocksize);
+
+ if (!dm[zone].dm_bh) {
+ adfs_error(sb, "unable to read map");
+ goto error_free;
+ }
+ }
+
+ /* adjust the limits for the first and last map zones */
+ i = zone - 1;
+ dm[0].dm_startblk = 0;
+ dm[0].dm_startbit = ADFS_DR_SIZE_BITS;
+ dm[i].dm_endbit = (dr->disc_size_high << (32 - dr->log2bpmb)) +
+ (dr->disc_size >> dr->log2bpmb) +
+ (ADFS_DR_SIZE_BITS - i * zone_size);
+
+ if (adfs_checkmap(sb, dm))
+ return dm;
+
+ adfs_error(sb, NULL, "map corrupted");
+
+error_free:
+ while (--zone >= 0)
+ brelse(dm[zone].dm_bh);
+
+ kfree(dm);
+ return NULL;
+}
+
+static inline unsigned long adfs_discsize(struct adfs_discrecord *dr, int block_bits)
+{
+ unsigned long discsize;
+
+ discsize = le32_to_cpu(dr->disc_size_high) << (32 - block_bits);
+ discsize |= le32_to_cpu(dr->disc_size) >> block_bits;
+
+ return discsize;
+}
+
struct super_block *adfs_read_super(struct super_block *sb, void *data, int silent)
{
struct adfs_discrecord *dr;
struct buffer_head *bh;
+ struct object_info root_obj;
unsigned char *b_data;
kdev_t dev = sb->s_dev;
- int i, j;
/* set default options */
sb->u.adfs_sb.s_uid = 0;
@@ -180,7 +328,7 @@ struct super_block *adfs_read_super(struct super_block *sb, void *data, int sile
lock_super(sb);
set_blocksize(dev, BLOCK_SIZE);
if (!(bh = bread(dev, ADFS_DISCRECORD / BLOCK_SIZE, BLOCK_SIZE))) {
- adfs_error(sb, NULL, "unable to read superblock");
+ adfs_error(sb, "unable to read superblock");
goto error_unlock;
}
@@ -192,8 +340,19 @@ struct super_block *adfs_read_super(struct super_block *sb, void *data, int sile
"%s.\n", kdevname(dev));
goto error_free_bh;
}
+
dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
+ /*
+ * Do some sanity checks on the ADFS disc record
+ */
+ if (adfs_checkdiscrecord(dr)) {
+ if (!silent)
+ printk("VPS: Can't find an adfs filesystem on dev "
+ "%s.\n", kdevname(dev));
+ goto error_free_bh;
+ }
+
sb->s_blocksize_bits = dr->log2secsize;
sb->s_blocksize = 1 << sb->s_blocksize_bits;
if (sb->s_blocksize != BLOCK_SIZE &&
@@ -204,13 +363,13 @@ struct super_block *adfs_read_super(struct super_block *sb, void *data, int sile
set_blocksize(dev, sb->s_blocksize);
bh = bread(dev, ADFS_DISCRECORD / sb->s_blocksize, sb->s_blocksize);
if (!bh) {
- adfs_error(sb, NULL, "couldn't read superblock on "
+ adfs_error(sb, "couldn't read superblock on "
"2nd try.");
goto error_unlock;
}
b_data = bh->b_data + (ADFS_DISCRECORD % sb->s_blocksize);
if (adfs_checkbblk(b_data)) {
- adfs_error(sb, NULL, "disc record mismatch, very weird!");
+ adfs_error(sb, "disc record mismatch, very weird!");
goto error_free_bh;
}
dr = (struct adfs_discrecord *)(b_data + ADFS_DR_OFFSET);
@@ -221,92 +380,66 @@ struct super_block *adfs_read_super(struct super_block *sb, void *data, int sile
"%s.\n", kdevname(dev));
goto error_free_bh;
}
- /* blocksize on this device should now be set to the adfs log2secsize */
- sb->u.adfs_sb.s_sbh = bh;
- sb->u.adfs_sb.s_dr = dr;
-
- /* s_zone_size = size of 1 zone (1 sector) * bits_in_byte - zone_spare =>
- * number of map bits in a zone
- */
- sb->u.adfs_sb.s_zone_size = (8 << dr->log2secsize) - dr->zone_spare;
-
- /* s_ids_per_zone = bit size of 1 zone / min. length of fragment block =>
- * number of ids in one zone
+ /*
+ * blocksize on this device should now be set to the ADFS log2secsize
*/
- sb->u.adfs_sb.s_ids_per_zone = sb->u.adfs_sb.s_zone_size / (dr->idlen + 1);
-
- /* s_idlen = length of 1 id */
- sb->u.adfs_sb.s_idlen = dr->idlen;
-
- /* map size (in sectors) = number of zones */
- sb->u.adfs_sb.s_map_size = dr->nzones;
-
- /* zonesize = size of sector - zonespare */
- sb->u.adfs_sb.s_zonesize = (sb->s_blocksize << 3) - dr->zone_spare;
- /* map start (in sectors) = start of zone (number of zones) / 2 */
- sb->u.adfs_sb.s_map_block = (dr->nzones >> 1) * sb->u.adfs_sb.s_zone_size -
- ((dr->nzones > 1) ? 8 * ADFS_DR_SIZE : 0);
+ sb->s_magic = ADFS_SUPER_MAGIC;
+ sb->u.adfs_sb.s_idlen = dr->idlen;
+ sb->u.adfs_sb.s_map_size = dr->nzones | (dr->nzones_high << 8);
+ sb->u.adfs_sb.s_map2blk = dr->log2bpmb - dr->log2secsize;
+ sb->u.adfs_sb.s_size = adfs_discsize(dr, sb->s_blocksize_bits);
+ sb->u.adfs_sb.s_version = dr->format_version;
+ sb->u.adfs_sb.s_log2sharesize = dr->log2sharesize;
- /* (signed) number of bits to shift left a map address to a sector address */
- sb->u.adfs_sb.s_map2blk = dr->log2bpmb - dr->log2secsize;
-
- if (sb->u.adfs_sb.s_map2blk >= 0)
- sb->u.adfs_sb.s_map_block <<= sb->u.adfs_sb.s_map2blk;
- else
- sb->u.adfs_sb.s_map_block >>= -sb->u.adfs_sb.s_map2blk;
-
- printk(KERN_DEBUG "ADFS: zone size %d, IDs per zone %d, map address %X size %d sectors\n",
- sb->u.adfs_sb.s_zone_size, sb->u.adfs_sb.s_ids_per_zone,
- sb->u.adfs_sb.s_map_block, sb->u.adfs_sb.s_map_size);
- printk(KERN_DEBUG "ADFS: sector size %d, map bit size %d, share size %d\n",
- 1 << dr->log2secsize, 1 << dr->log2bpmb,
- 1 << (dr->log2secsize + dr->log2sharesize));
-
- sb->s_magic = ADFS_SUPER_MAGIC;
-
- sb->u.adfs_sb.s_map = kmalloc(sb->u.adfs_sb.s_map_size *
- sizeof(struct buffer_head *), GFP_KERNEL);
- if (sb->u.adfs_sb.s_map == NULL) {
- adfs_error(sb, NULL, "not enough memory");
+ sb->u.adfs_sb.s_map = adfs_read_map(sb, dr);
+ if (!sb->u.adfs_sb.s_map)
goto error_free_bh;
- }
- for (i = 0; i < sb->u.adfs_sb.s_map_size; i++) {
- sb->u.adfs_sb.s_map[i] = bread(dev,
- sb->u.adfs_sb.s_map_block + i,
- sb->s_blocksize);
- if (!sb->u.adfs_sb.s_map[i]) {
- for (j = 0; j < i; j++)
- brelse(sb->u.adfs_sb.s_map[j]);
- kfree(sb->u.adfs_sb.s_map);
- adfs_error(sb, NULL, "unable to read map");
- goto error_free_bh;
- }
- }
- if (!adfs_checkmap(sb)) {
- for (i = 0; i < sb->u.adfs_sb.s_map_size; i++)
- brelse(sb->u.adfs_sb.s_map[i]);
- adfs_error(sb, NULL, "map corrupted");
- goto error_free_bh;
- }
+ brelse(bh);
- dr = (struct adfs_discrecord *)(sb->u.adfs_sb.s_map[0]->b_data + 4);
+ /*
+ * set up enough so that we can read an inode
+ */
+ sb->s_op = &adfs_sops;
unlock_super(sb);
+ dr = (struct adfs_discrecord *)(sb->u.adfs_sb.s_map[0].dm_bh->b_data + 4);
+
+ root_obj.parent_id = root_obj.file_id = le32_to_cpu(dr->root);
+ root_obj.name_len = 0;
+ root_obj.loadaddr = 0;
+ root_obj.execaddr = 0;
+ root_obj.size = ADFS_NEWDIR_SIZE;
+ root_obj.attr = ADFS_NDA_DIRECTORY | ADFS_NDA_OWNER_READ |
+ ADFS_NDA_OWNER_WRITE | ADFS_NDA_PUBLIC_READ;
+
/*
- * set up enough so that it can read an inode
+ * If this is a F+ disk with variable length directories,
+ * get the root_size from the disc record.
*/
- sb->s_op = &adfs_sops;
- sb->u.adfs_sb.s_root = adfs_inode_generate(dr->root, 0);
- sb->s_root = d_alloc_root(iget(sb, sb->u.adfs_sb.s_root));
+ if (sb->u.adfs_sb.s_version) {
+ root_obj.size = dr->root_size;
+ sb->u.adfs_sb.s_dir = &adfs_fplus_dir_ops;
+ sb->u.adfs_sb.s_namelen = ADFS_FPLUS_NAME_LEN;
+ } else {
+ sb->u.adfs_sb.s_dir = &adfs_f_dir_ops;
+ sb->u.adfs_sb.s_namelen = ADFS_F_NAME_LEN;
+ }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+ sb->s_root = d_alloc_root(adfs_iget(sb, &root_obj));
+#else
+ sb->s_root = d_alloc_root(adfs_iget(sb, &root_obj), NULL);
+#endif
if (!sb->s_root) {
+ int i;
+
for (i = 0; i < sb->u.adfs_sb.s_map_size; i++)
- brelse(sb->u.adfs_sb.s_map[i]);
- brelse(bh);
- adfs_error(sb, NULL, "get root inode failed\n");
+ brelse(sb->u.adfs_sb.s_map[i].dm_bh);
+ kfree(sb->u.adfs_sb.s_map);
+ adfs_error(sb, "get root inode failed\n");
goto error_dec_use;
}
return sb;
@@ -322,65 +455,6 @@ error:
return NULL;
}
-static int adfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
-{
- struct statfs tmp;
- const unsigned int nidlen = sb->u.adfs_sb.s_idlen + 1;
-
- tmp.f_type = ADFS_SUPER_MAGIC;
- tmp.f_bsize = sb->s_blocksize;
- tmp.f_blocks = sb->u.adfs_sb.s_dr->disc_size_high << (32 - sb->s_blocksize_bits) |
- sb->u.adfs_sb.s_dr->disc_size >> sb->s_blocksize_bits;
- tmp.f_files = tmp.f_blocks >> nidlen;
- {
- unsigned int i, j = 0;
- const unsigned mask = (1 << (nidlen - 1)) - 1;
- for (i = 0; i < sb->u.adfs_sb.s_map_size; i++) {
- const char *map = sb->u.adfs_sb.s_map[i]->b_data;
- unsigned freelink, mapindex = 24;
- j -= nidlen;
- do {
- unsigned char k, l, m;
- unsigned off = (mapindex - nidlen) >> 3;
- unsigned rem;
- const unsigned boff = mapindex & 7;
-
- /* get next freelink */
-
- k = map[off++];
- l = map[off++];
- m = map[off++];
- freelink = (m << 16) | (l << 8) | k;
- rem = freelink >> (boff + nidlen - 1);
- freelink = (freelink >> boff) & mask;
- mapindex += freelink;
-
- /* find its length and add it to running total */
-
- while (rem == 0) {
- j += 8;
- rem = map[off++];
- }
- if ((rem & 0xff) == 0) j+=8, rem>>=8;
- if ((rem & 0xf) == 0) j+=4, rem>>=4;
- if ((rem & 0x3) == 0) j+=2, rem>>=2;
- if ((rem & 0x1) == 0) j+=1;
- j += nidlen - boff;
- if (freelink <= nidlen) break;
- } while (mapindex < 8 * sb->s_blocksize);
- if (mapindex > 8 * sb->s_blocksize)
- adfs_error(sb, NULL, "oversized free fragment\n");
- else if (freelink)
- adfs_error(sb, NULL, "undersized free fragment\n");
- }
- tmp.f_bfree = tmp.f_bavail = j <<
- (sb->u.adfs_sb.s_dr->log2bpmb - sb->s_blocksize_bits);
- }
- tmp.f_ffree = tmp.f_bfree >> nidlen;
- tmp.f_namelen = ADFS_NAME_LEN;
- return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
-}
-
static struct file_system_type adfs_fs_type = {
"adfs", FS_REQUIRES_DEV, adfs_read_super, NULL
};
diff --git a/fs/affs/dir.c b/fs/affs/dir.c
index f126dcbb8..b554daf0c 100644
--- a/fs/affs/dir.c
+++ b/fs/affs/dir.c
@@ -28,17 +28,9 @@ static int affs_readdir(struct file *, void *, filldir_t);
static ssize_t affs_dir_read(struct file *, char *, size_t, loff_t *);
static struct file_operations affs_dir_operations = {
- NULL, /* lseek - default */
- affs_dir_read, /* read */
- NULL, /* write - bad */
- affs_readdir, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- file_fsync /* default fsync */
+ read: affs_dir_read,
+ readdir: affs_readdir,
+ fsync: file_fsync,
};
/*
@@ -55,14 +47,6 @@ struct inode_operations affs_dir_inode_operations = {
affs_rmdir, /* rmdir */
NULL, /* mknod */
affs_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permissions */
- NULL /* revalidate */
};
static ssize_t
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 7a751e40b..8881fe3e4 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -44,19 +44,10 @@ static ssize_t affs_file_write_ofs(struct file *filp, const char *buf, size_t cn
static int alloc_ext_cache(struct inode *inode);
static struct file_operations affs_file_operations = {
- NULL, /* lseek - default */
- generic_file_read, /* read */
- affs_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- generic_file_mmap, /* mmap */
- NULL, /* no special open */
- NULL, /* flush */
- NULL, /* release */
- file_fsync, /* brute force, but works */
- NULL, /* fasync */
- NULL /* lock */
+ read: generic_file_read,
+ write: affs_file_write,
+ mmap: generic_file_mmap,
+ fsync: file_fsync,
};
struct inode_operations affs_file_inode_operations = {
@@ -72,28 +63,15 @@ struct inode_operations affs_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- affs_bmap, /* get_block */
- block_read_full_page, /* readpage */
- NULL, /* writepage */
affs_truncate, /* truncate */
NULL, /* permission */
NULL /* revalidate */
};
static struct file_operations affs_file_operations_ofs = {
- NULL, /* lseek - default */
- affs_file_read_ofs, /* read */
- affs_file_write_ofs, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open */
- NULL, /* flush */
- NULL, /* release */
- file_fsync, /* brute force, but works */
- NULL, /* fasync */
- NULL /* lock */
+ read: affs_file_read_ofs,
+ write: affs_file_write_ofs,
+ fsync: file_fsync,
};
struct inode_operations affs_file_inode_operations_ofs = {
@@ -109,9 +87,6 @@ struct inode_operations affs_file_inode_operations_ofs = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
affs_truncate, /* truncate */
NULL, /* permission */
NULL /* revalidate */
@@ -341,6 +316,37 @@ affs_bmap(struct inode *inode, int block)
return key;
}
+/* AFFS is currently broken */
+static int affs_get_block(struct inode *inode, long block, struct buffer_head *bh, int create)
+{
+ BUG();
+ return -1;
+}
+static int affs_writepage(struct dentry *dentry, struct page *page)
+{
+ return block_write_full_page(page,affs_get_block);
+}
+static int affs_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,affs_get_block);
+}
+static int affs_prepare_write(struct page *page, unsigned from, unsigned to)
+{
+ return cont_prepare_write(page,from,to,affs_get_block,
+ &((struct inode*)page->mapping->host)->u.affs_i.mmu_private);
+}
+static int _affs_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,affs_get_block);
+}
+struct address_space_operations affs_aops = {
+ readpage: affs_readpage,
+ writepage: affs_writepage,
+ prepare_write: affs_prepare_write,
+ commit_write: generic_commit_write,
+ bmap: _affs_bmap
+};
+
/* With the affs, getting a random block from a file is not
* a simple business. Since this fs does not allow holes,
* it may be necessary to allocate all the missing blocks
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 9b05ec062..ed4993e36 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -166,16 +166,20 @@ affs_read_inode(struct inode *inode)
if (S_ISREG(inode->i_mode)) {
if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
inode->i_op = &affs_file_inode_operations_ofs;
- } else {
- inode->i_op = &affs_file_inode_operations;
+ return;
}
+ inode->i_op = &affs_file_inode_operations;
+ inode->i_mapping->a_ops = &affs_aops;
+ inode->u.affs_i.mmu_private = inode->i_size;
} else if (S_ISDIR(inode->i_mode)) {
/* Maybe it should be controlled by mount parameter? */
inode->i_mode |= S_ISVTX;
inode->i_op = &affs_dir_inode_operations;
}
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &affs_symlink_inode_operations;
+ else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_data.a_ops = &affs_symlink_aops;
+ }
}
void
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index aad5b8f14..d2c27b9d1 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -275,9 +275,11 @@ affs_create(struct inode *dir, struct dentry *dentry, int mode)
pr_debug("AFFS: ino=%lu\n",inode->i_ino);
if (dir->i_sb->u.affs_sb.s_flags & SF_OFS)
inode->i_op = &affs_file_inode_operations_ofs;
- else
+ else {
inode->i_op = &affs_file_inode_operations;
-
+ inode->i_mapping->a_ops = &affs_aops;
+ inode->u.affs_i.mmu_private = inode->i_size;
+ }
error = affs_add_entry(dir,NULL,inode,dentry,ST_FILE);
if (error)
goto out_iput;
@@ -401,7 +403,8 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
if (!inode)
goto out;
- inode->i_op = &affs_symlink_inode_operations;
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_data.a_ops = &affs_symlink_aops;
inode->i_mode = S_IFLNK | 0777;
inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
error = -EIO;
diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c
index 6aad1c222..885d5099d 100644
--- a/fs/affs/symlink.c
+++ b/fs/affs/symlink.c
@@ -71,8 +71,6 @@ fail:
return err;
}
-struct inode_operations affs_symlink_inode_operations = {
- readlink: page_readlink,
- follow_link: page_follow_link,
+struct address_space_operations affs_symlink_aops = {
readpage: affs_symlink_readpage,
};
diff --git a/fs/autofs/dir.c b/fs/autofs/dir.c
index ae53396af..a62fd6c54 100644
--- a/fs/autofs/dir.c
+++ b/fs/autofs/dir.c
@@ -43,30 +43,12 @@ static struct dentry *autofs_dir_lookup(struct inode *dir,struct dentry *dentry)
}
static struct file_operations autofs_dir_operations = {
- NULL, /* llseek */
- NULL, /* read */
- NULL, /* write */
- autofs_dir_readdir, /* readdir */
+ readdir: autofs_dir_readdir,
};
struct inode_operations autofs_dir_inode_operations = {
&autofs_dir_operations, /* file operations */
NULL, /* create */
autofs_dir_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
diff --git a/fs/autofs/init.c b/fs/autofs/init.c
index 5c31dc889..4c9e8fe76 100644
--- a/fs/autofs/init.c
+++ b/fs/autofs/init.c
@@ -31,8 +31,8 @@ static void __exit exit_autofs_fs(void)
unregister_filesystem(&autofs_fs_type);
}
-module_init(init_autofs_fs)
-module_exit(exit_autofs_fs)
+module_init(init_autofs_fs);
+module_exit(exit_autofs_fs);
#ifdef DEBUG
void autofs_say(const char *name, int len)
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 46fc4503e..e2c03ff34 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -24,12 +24,8 @@ static int autofs_root_mkdir(struct inode *,struct dentry *,int);
static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
static struct file_operations autofs_root_operations = {
- NULL, /* llseek */
- NULL, /* read */
- NULL, /* write */
- autofs_root_readdir, /* readdir */
- NULL, /* poll */
- autofs_root_ioctl, /* ioctl */
+ readdir: autofs_root_readdir,
+ ioctl: autofs_root_ioctl,
};
struct inode_operations autofs_root_inode_operations = {
@@ -41,16 +37,6 @@ struct inode_operations autofs_root_inode_operations = {
autofs_root_symlink, /* symlink */
autofs_root_mkdir, /* mkdir */
autofs_root_rmdir, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index e8487efd6..102f7213e 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -12,7 +12,7 @@
/* Internal header file for autofs */
-#include <linux/auto_fs.h>
+#include <linux/auto_fs4.h>
#include <linux/list.h>
/* This is the range of ioctl() numbers we claim as ours */
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 1b512ee1c..9c8bd133f 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -140,7 +140,8 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
*gid = current->gid;
*pgrp = current->pgrp;
- *minproto = *maxproto = AUTOFS_MAX_PROTO_VERSION;
+ *minproto = AUTOFS_MIN_PROTO_VERSION;
+ *maxproto = AUTOFS_MAX_PROTO_VERSION;
*pipefd = -1;
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 464c940b8..b3b45fc0b 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -86,7 +86,7 @@ static int autofs4_write(struct file *file, const void *addr, int bytes)
static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
struct autofs_wait_queue *wq,
- enum autofs_packet_type type)
+ int type)
{
union autofs_packet_union pkt;
size_t pktsz;
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index bff2689a0..931a32a4e 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -30,19 +30,19 @@ static int return_EIO(void)
static struct file_operations bad_file_ops =
{
- EIO_ERROR, /* lseek */
- EIO_ERROR, /* read */
- EIO_ERROR, /* write */
- EIO_ERROR, /* readdir */
- EIO_ERROR, /* select */
- EIO_ERROR, /* ioctl */
- EIO_ERROR, /* mmap */
- EIO_ERROR, /* open */
- EIO_ERROR, /* flush */
- EIO_ERROR, /* release */
- EIO_ERROR, /* fsync */
- EIO_ERROR, /* fasync */
- EIO_ERROR, /* lock */
+ llseek: EIO_ERROR,
+ read: EIO_ERROR,
+ write: EIO_ERROR,
+ readdir: EIO_ERROR,
+ poll: EIO_ERROR,
+ ioctl: EIO_ERROR,
+ mmap: EIO_ERROR,
+ open: EIO_ERROR,
+ flush: EIO_ERROR,
+ release: EIO_ERROR,
+ fsync: EIO_ERROR,
+ fasync: EIO_ERROR,
+ lock: EIO_ERROR,
};
struct inode_operations bad_inode_ops =
@@ -59,9 +59,6 @@ struct inode_operations bad_inode_ops =
EIO_ERROR, /* rename */
EIO_ERROR, /* readlink */
bad_follow_link, /* follow_link */
- EIO_ERROR, /* get_block */
- EIO_ERROR, /* readpage */
- EIO_ERROR, /* writepage */
EIO_ERROR, /* truncate */
EIO_ERROR, /* permission */
EIO_ERROR /* revalidate */
diff --git a/fs/bfs/bfs_defs.h b/fs/bfs/bfs_defs.h
index 54d7dad29..c2756cdb9 100644
--- a/fs/bfs/bfs_defs.h
+++ b/fs/bfs/bfs_defs.h
@@ -5,7 +5,6 @@
#define su_lf_ioff u.bfs_sb.si_lf_ioff
#define su_lf_sblk u.bfs_sb.si_lf_sblk
#define su_lf_eblk u.bfs_sb.si_lf_eblk
-#define su_bmap u.bfs_sb.si_bmap
#define su_imap u.bfs_sb.si_imap
#define su_sbh u.bfs_sb.si_sbh
#define su_bfs_sb u.bfs_sb.si_bfs_sb
@@ -13,3 +12,6 @@
#define iu_dsk_ino u.bfs_i.i_dsk_ino
#define iu_sblock u.bfs_i.i_sblock
#define iu_eblock u.bfs_i.i_eblock
+
+#define printf(format, args...) \
+ printk(KERN_ERR "BFS-fs: " __FUNCTION__ "(): " format, ## args)
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index b6159be85..83b3e517b 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -14,9 +14,9 @@
#undef DEBUG
#ifdef DEBUG
-#define DBG(x...) printk(x)
+#define dprintf(x...) printf(x)
#else
-#define DBG(x...)
+#define dprintf(x...)
#endif
static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino);
@@ -38,14 +38,13 @@ static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
int block;
if (!dir || !dir->i_sb || !S_ISDIR(dir->i_mode)) {
- printk(KERN_ERR "BFS-fs: %s(): Bad inode or not a directory %s:%08lx\n",
- __FUNCTION__, bdevname(dev), dir->i_ino);
+ printf("Bad inode or not a directory %s:%08lx\n", bdevname(dev), dir->i_ino);
return -EBADF;
}
if (f->f_pos & (BFS_DIRENT_SIZE-1)) {
- printk(KERN_ERR "BFS-fs: %s(): Bad f_pos=%08lx for %s:%08lx\n",
- __FUNCTION__, (unsigned long)f->f_pos, bdevname(dev), dir->i_ino);
+ printf("Bad f_pos=%08lx for %s:%08lx\n", (unsigned long)f->f_pos,
+ bdevname(dev), dir->i_ino);
return -EBADF;
}
@@ -77,18 +76,9 @@ static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
}
static struct file_operations bfs_dir_operations = {
- llseek: NULL,
read: bfs_dir_read,
- write: NULL,
readdir: bfs_readdir,
- poll: NULL,
- ioctl: NULL,
- mmap: NULL,
- open: NULL,
- flush: NULL,
- release: NULL,
fsync: file_fsync,
- fasync: NULL,
};
extern void dump_imap(const char *, struct super_block *);
@@ -117,6 +107,7 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode)
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = inode->i_blksize = 0;
inode->i_op = &bfs_file_inops;
+ inode->i_mapping->a_ops = &bfs_aops;
inode->i_mode = mode;
inode->i_ino = inode->iu_dsk_ino = ino;
inode->iu_sblock = inode->iu_eblock = 0;
@@ -189,9 +180,8 @@ static int bfs_unlink(struct inode * dir, struct dentry * dentry)
goto out_brelse;
if (!inode->i_nlink) {
- printk(KERN_WARNING
- "BFS-fs: %s(): unlinking non-existent file %s:%lu (nlink=%d)\n",
- __FUNCTION__, bdevname(inode->i_dev), inode->i_ino, inode->i_nlink);
+ printf("unlinking non-existent file %s:%lu (nlink=%d)\n", bdevname(inode->i_dev),
+ inode->i_ino, inode->i_nlink);
inode->i_nlink = 1;
}
de->ino = 0;
@@ -276,14 +266,6 @@ struct inode_operations bfs_dir_inops = {
rmdir: NULL,
mknod: NULL,
rename: bfs_rename,
- readlink: NULL,
- follow_link: NULL,
- get_block: NULL,
- readpage: NULL,
- writepage: NULL,
- truncate: NULL,
- permission: NULL,
- revalidate: NULL
};
static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino)
@@ -294,7 +276,7 @@ static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int
kdev_t dev;
int i;
- DBG(KERN_ERR "BFS-fs: %s(%s,%d)\n", __FUNCTION__, name, namelen);
+ dprintf("name=%s, namelen=%d\n", name, namelen);
if (!namelen)
return -ENOENT;
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
index 9e7503626..c3d5a8905 100644
--- a/fs/bfs/file.c
+++ b/fs/bfs/file.c
@@ -5,68 +5,149 @@
*/
#include <linux/fs.h>
+#include <linux/locks.h>
#include <linux/bfs_fs.h>
+#include <linux/smp_lock.h>
#include "bfs_defs.h"
#undef DEBUG
#ifdef DEBUG
-#define DBG(x...) printk(x)
+#define dprintf(x...) printf(x)
#else
-#define DBG(x...)
+#define dprintf(x...)
#endif
-static ssize_t bfs_file_write(struct file * f, const char * buf, size_t count, loff_t *ppos)
-{
- return generic_file_write(f, buf, count, ppos, block_write_partial_page);
-}
-
static struct file_operations bfs_file_operations = {
- llseek: NULL,
read: generic_file_read,
- write: bfs_file_write,
- readdir: NULL,
- poll: NULL,
- ioctl: NULL,
+ write: generic_file_write,
mmap: generic_file_mmap,
- open: NULL,
- flush: NULL,
- release: NULL,
- fsync: NULL,
- fasync: NULL,
};
+static int bfs_move_block(unsigned long from, unsigned long to, kdev_t dev)
+{
+ struct buffer_head *bh, *new = NULL;
+
+ bh = bread(dev, from, BFS_BSIZE);
+ if (!bh)
+ return -EIO;
+ new = getblk(dev, to, BFS_BSIZE);
+ memcpy(new->b_data, bh->b_data, bh->b_size);
+ mark_buffer_dirty(new, 1);
+ bforget(bh);
+ brelse(new);
+ return 0;
+}
+
+static int bfs_move_blocks(kdev_t dev, unsigned long start, unsigned long end,
+ unsigned long where)
+{
+ unsigned long i;
+
+ dprintf("%08lx-%08lx->%08lx\n", start, end, where);
+ for (i = start; i <= end; i++)
+ if(bfs_move_block(i, where + i, dev)) {
+ dprintf("failed to move block %08lx -> %08lx\n", i, where + i);
+ return -EIO;
+ }
+ return 0;
+}
+
static int bfs_get_block(struct inode * inode, long block,
struct buffer_head * bh_result, int create)
{
- long phys = inode->iu_sblock + block;
- if (!create || phys <= inode->iu_eblock) {
+ long phys, next_free_block;
+ int err;
+ struct super_block *s = inode->i_sb;
+
+ if (block < 0 || block > s->su_blocks)
+ return -EIO;
+
+ phys = inode->iu_sblock + block;
+ if (!create) {
+ if (phys <= inode->iu_eblock) {
+ dprintf("c=%d, b=%08lx, phys=%08lx (granted)\n", create, block, phys);
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ }
+ return 0;
+ }
+
+ /* if the file is not empty and the requested block is within the range
+ of blocks allocated for this file, we can grant it */
+ if (inode->i_size && phys <= inode->iu_eblock) {
+ dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n", create, block, phys);
bh_result->b_dev = inode->i_dev;
bh_result->b_blocknr = phys;
bh_result->b_state |= (1UL << BH_Mapped);
return 0;
- }
- /* no support for file migration, working on it */
- return -EIO;
+ }
+
+ /* the rest has to be protected against itself */
+ lock_kernel();
+
+ /* if the last data block for this file is the last allocated block, we can
+ extend the file trivially, without moving it anywhere */
+ if (inode->iu_eblock == s->su_lf_eblk) {
+ dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n", create, block, phys);
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ s->su_lf_eblk = inode->iu_eblock = inode->iu_sblock + block;
+ mark_inode_dirty(inode);
+ mark_buffer_dirty(s->su_sbh, 1);
+ err = 0;
+ goto out;
+ }
+
+ /* Ok, we have to move this entire file to the next free block */
+ next_free_block = s->su_lf_eblk + 1;
+ if (inode->iu_sblock) { /* if data starts on block 0 then there is no data */
+ err = bfs_move_blocks(inode->i_dev, inode->iu_sblock, inode->iu_eblock, next_free_block);
+ if (err) {
+ dprintf("failed to move ino=%08lx -> possible fs corruption\n", inode->i_ino);
+ goto out;
+ }
+ } else
+ err = 0;
+
+ inode->iu_sblock = next_free_block;
+ s->su_lf_eblk = inode->iu_eblock = next_free_block + block;
+ mark_inode_dirty(inode);
+ mark_buffer_dirty(s->su_sbh, 1);
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = inode->iu_sblock + block;
+ bh_result->b_state |= (1UL << BH_Mapped);
+out:
+ unlock_kernel();
+ return err;
+}
+
+static int bfs_writepage(struct dentry *dentry, struct page *page)
+{
+ return block_write_full_page(page,bfs_get_block);
+}
+static int bfs_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,bfs_get_block);
+}
+static int bfs_prepare_write(struct page *page, unsigned from, unsigned to)
+{
+ return block_prepare_write(page,from,to,bfs_get_block);
+}
+static int bfs_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,bfs_get_block);
}
+struct address_space_operations bfs_aops = {
+ readpage: bfs_readpage,
+ writepage: bfs_writepage,
+ prepare_write: bfs_prepare_write,
+ commit_write: generic_commit_write,
+ bmap: bfs_bmap
+};
struct inode_operations bfs_file_inops = {
default_file_ops: &bfs_file_operations,
- create: NULL,
- lookup: NULL,
- link: NULL,
- unlink: NULL,
- symlink: NULL,
- mkdir: NULL,
- rmdir: NULL,
- mknod: NULL,
- rename: NULL,
- readlink: NULL,
- follow_link: NULL,
- get_block: bfs_get_block,
- readpage: block_read_full_page,
- writepage: block_write_full_page,
- truncate: NULL,
- permission: NULL,
- revalidate: NULL
};
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index c0ee15dc4..14e440f27 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -5,7 +5,6 @@
* From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/slab.h>
@@ -18,15 +17,15 @@
#include "bfs_defs.h"
MODULE_AUTHOR("Tigran A. Aivazian");
-MODULE_DESCRIPTION("UnixWare BFS filesystem for Linux");
+MODULE_DESCRIPTION("SCO UnixWare BFS filesystem for Linux");
EXPORT_NO_SYMBOLS;
#undef DEBUG
#ifdef DEBUG
-#define DBG(x...) printk(x)
+#define dprintf(x...) printf(x)
#else
-#define DBG(x...)
+#define dprintf(x...)
#endif
void dump_imap(const char *prefix, struct super_block * s);
@@ -40,8 +39,7 @@ static void bfs_read_inode(struct inode * inode)
int block, off;
if (ino < BFS_ROOT_INO || ino > inode->i_sb->su_lasti) {
- printk(KERN_ERR "BFS-fs: %s(): Bad inode number %s:%08lx\n",
- __FUNCTION__, bdevname(dev), ino);
+ printf("Bad inode number %s:%08lx\n", bdevname(dev), ino);
make_bad_inode(inode);
return;
}
@@ -49,8 +47,7 @@ static void bfs_read_inode(struct inode * inode)
block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
bh = bread(dev, block, BFS_BSIZE);
if (!bh) {
- printk(KERN_ERR "BFS-fs: %s(): Unable to read inode %s:%08lx\n",
- __FUNCTION__, bdevname(dev), ino);
+ printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
make_bad_inode(inode);
return;
}
@@ -65,6 +62,7 @@ static void bfs_read_inode(struct inode * inode)
} else if (di->i_vtype == BFS_VREG) {
inode->i_mode |= S_IFREG;
inode->i_op = &bfs_file_inops;
+ inode->i_mapping->a_ops = &bfs_aops;
} else
inode->i_op = NULL;
@@ -94,16 +92,14 @@ static void bfs_write_inode(struct inode * inode)
int block, off;
if (ino < BFS_ROOT_INO || ino > inode->i_sb->su_lasti) {
- printk(KERN_ERR "BFS-fs: %s(): Bad inode number %s:%08lx\n",
- __FUNCTION__, bdevname(dev), ino);
+ printf("Bad inode number %s:%08lx\n", bdevname(dev), ino);
return;
}
block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
bh = bread(dev, block, BFS_BSIZE);
if (!bh) {
- printk(KERN_ERR "BFS-fs: %s(): Unable to read inode %s:%08lx\n",
- __FUNCTION__, bdevname(dev), ino);
+ printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
return;
}
@@ -140,30 +136,12 @@ static void bfs_delete_inode(struct inode * inode)
int block, off;
struct super_block * s = inode->i_sb;
- DBG(KERN_ERR "%s(ino=%08lx)\n", __FUNCTION__, inode->i_ino);
+ dprintf("ino=%08lx\n", inode->i_ino);
- if (!inode)
+ if (!inode || !inode->i_dev || inode->i_count > 1 || inode->i_nlink || !s)
return;
- if (!inode->i_dev) {
- printk(KERN_ERR "BFS-fs: free_inode(%08lx) !dev\n", inode->i_ino);
- return;
- }
- if (inode->i_count > 1) {
- printk(KERN_ERR "BFS-fs: free_inode(%08lx) count=%d\n",
- inode->i_ino, inode->i_count);
- return;
- }
- if (inode->i_nlink) {
- printk(KERN_ERR "BFS-fs: free_inode(%08lx) nlink=%d\n",
- inode->i_ino, inode->i_nlink);
- return;
- }
- if (!inode->i_sb) {
- printk(KERN_ERR "BFS-fs: free_inode(%08lx) !sb\n", inode->i_ino);
- return;
- }
if (inode->i_ino < BFS_ROOT_INO || inode->i_ino > inode->i_sb->su_lasti) {
- printk(KERN_ERR "BFS-fs: free_inode(%08lx) invalid ino\n", inode->i_ino);
+ printf("invalid ino=%08lx\n", inode->i_ino);
return;
}
@@ -173,8 +151,7 @@ static void bfs_delete_inode(struct inode * inode)
block = (ino - BFS_ROOT_INO)/BFS_INODES_PER_BLOCK + 1;
bh = bread(dev, block, BFS_BSIZE);
if (!bh) {
- printk(KERN_ERR "BFS-fs: %s(): Unable to read inode %s:%08lx\n",
- __FUNCTION__, bdevname(dev), ino);
+ printf("Unable to read inode %s:%08lx\n", bdevname(dev), ino);
return;
}
off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK;
@@ -189,6 +166,14 @@ static void bfs_delete_inode(struct inode * inode)
di->i_sblock = 0;
mark_buffer_dirty(bh, 1);
brelse(bh);
+
+ /* if this was the last file, make the previous
+ block "last files last block" even if there is no real file there,
+ saves us 1 gap */
+ if (s->su_lf_eblk == inode->iu_eblock) {
+ s->su_lf_eblk = inode->iu_sblock - 1;
+ mark_buffer_dirty(s->su_sbh, 1);
+ }
clear_inode(inode);
}
@@ -196,7 +181,6 @@ static void bfs_put_super(struct super_block *s)
{
brelse(s->su_sbh);
kfree(s->su_imap);
- kfree(s->su_bmap);
MOD_DEC_USE_COUNT;
}
@@ -251,7 +235,7 @@ void dump_imap(const char *prefix, struct super_block * s)
else
strcat(tmpbuf, "0");
}
- printk(KERN_ERR "BFS-fs: %s: lasti=%d <%s>\n", prefix, s->su_lasti, tmpbuf);
+ printk(KERN_ERR "BFS-fs: %s: lasti=%08lx <%s>\n", prefix, s->su_lasti, tmpbuf);
free_page((unsigned long)tmpbuf);
#endif
}
@@ -263,7 +247,7 @@ static struct super_block * bfs_read_super(struct super_block * s,
struct buffer_head * bh;
struct bfs_super_block * bfs_sb;
struct inode * inode;
- int i, imap_len, bmap_len;
+ int i, imap_len;
MOD_INC_USE_COUNT;
lock_super(s);
@@ -272,58 +256,43 @@ static struct super_block * bfs_read_super(struct super_block * s,
s->s_blocksize = BFS_BSIZE;
s->s_blocksize_bits = BFS_BSIZE_BITS;
- /* read ahead 8K to get inodes as we'll need them in a tick */
- bh = breada(dev, 0, BFS_BSIZE, 0, 8192);
+ bh = bread(dev, 0, BFS_BSIZE);
if(!bh)
goto out;
bfs_sb = (struct bfs_super_block *)bh->b_data;
if (bfs_sb->s_magic != BFS_MAGIC) {
if (!silent)
- printk(KERN_ERR "BFS-fs: No BFS filesystem on %s (magic=%08x)\n",
- bdevname(dev), bfs_sb->s_magic);
+ printf("No BFS filesystem on %s (magic=%08x)\n",
+ bdevname(dev), bfs_sb->s_magic);
goto out;
}
if (BFS_UNCLEAN(bfs_sb, s) && !silent)
- printk(KERN_WARNING "BFS-fs: %s is unclean\n", bdevname(dev));
+ printf("%s is unclean, continuing\n", bdevname(dev));
-#ifndef CONFIG_BFS_FS_WRITE
- s->s_flags |= MS_RDONLY;
-#endif
s->s_magic = BFS_MAGIC;
s->su_bfs_sb = bfs_sb;
s->su_sbh = bh;
s->su_lasti = (bfs_sb->s_start - BFS_BSIZE)/sizeof(struct bfs_inode)
+ BFS_ROOT_INO - 1;
- bmap_len = sizeof(struct bfs_bmap) * s->su_lasti;
- s->su_bmap = kmalloc(bmap_len, GFP_KERNEL);
- if (!s->su_bmap)
- goto out;
- memset(s->su_bmap, 0, bmap_len);
imap_len = s->su_lasti/8 + 1;
s->su_imap = kmalloc(imap_len, GFP_KERNEL);
- if (!s->su_imap) {
- kfree(s->su_bmap);
+ if (!s->su_imap)
goto out;
- }
memset(s->su_imap, 0, imap_len);
- for (i=0; i<BFS_ROOT_INO; i++) {
- s->su_bmap[i].start = s->su_bmap[i].end = 0;
+ for (i=0; i<BFS_ROOT_INO; i++)
set_bit(i, s->su_imap);
- }
s->s_op = &bfs_sops;
inode = iget(s, BFS_ROOT_INO);
if (!inode) {
kfree(s->su_imap);
- kfree(s->su_bmap);
goto out;
}
s->s_root = d_alloc_root(inode);
if (!s->s_root) {
iput(inode);
kfree(s->su_imap);
- kfree(s->su_bmap);
goto out;
}
@@ -335,10 +304,9 @@ static struct super_block * bfs_read_super(struct super_block * s,
s->su_lf_ioff = 0;
for (i=BFS_ROOT_INO; i<=s->su_lasti; i++) {
inode = iget(s,i);
- if (inode->iu_dsk_ino == 0) {
+ if (inode->iu_dsk_ino == 0)
s->su_freei++;
- s->su_bmap[i].start = s->su_bmap[i].end = 0;
- } else {
+ else {
set_bit(i, s->su_imap);
s->su_freeb -= inode->i_blocks;
if (inode->iu_eblock > s->su_lf_eblk) {
@@ -346,8 +314,6 @@ static struct super_block * bfs_read_super(struct super_block * s,
s->su_lf_sblk = inode->iu_sblock;
s->su_lf_ioff = BFS_INO2OFF(i);
}
- s->su_bmap[i].start = inode->iu_sblock;
- s->su_bmap[i].end = inode->iu_eblock;
}
iput(inode);
}
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 0d8a3c109..f4937eb91 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -405,7 +405,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
int elf_exec_fileno;
int retval, size, i;
unsigned long elf_entry, interp_load_addr = 0;
- unsigned long start_code, end_code, end_data;
+ unsigned long start_code, end_code, start_data, end_data;
struct elfhdr elf_ex;
struct elfhdr interp_elf_ex;
struct exec interp_ex;
@@ -470,6 +470,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
start_code = ~0UL;
end_code = 0;
+ start_data = 0;
end_data = 0;
for (i = 0; i < elf_ex.e_phnum; i++) {
@@ -586,6 +587,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
goto out_free_dentry;
/* OK, This is the point of no return */
+ current->mm->start_data = 0;
current->mm->end_data = 0;
current->mm->end_code = 0;
current->mm->mmap = NULL;
@@ -650,7 +652,10 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
}
k = elf_ppnt->p_vaddr;
if (k < start_code) start_code = k;
+ if (start_data < k) start_data = k;
+
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
+
if (k > elf_bss)
elf_bss = k;
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
@@ -669,6 +674,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
elf_brk += load_bias;
start_code += load_bias;
end_code += load_bias;
+ start_data += load_bias;
end_data += load_bias;
if (elf_interpreter) {
@@ -726,6 +732,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
current->mm->start_brk = current->mm->brk = elf_brk;
current->mm->end_code = end_code;
current->mm->start_code = start_code;
+ current->mm->start_data = start_data;
current->mm->end_data = end_data;
current->mm->start_stack = bprm->p;
@@ -740,6 +747,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
printk("(start_brk) %lx\n" , (long) current->mm->start_brk);
printk("(end_code) %lx\n" , (long) current->mm->end_code);
printk("(start_code) %lx\n" , (long) current->mm->start_code);
+ printk("(start_data) %lx\n" , (long) current->mm->start_data);
printk("(end_data) %lx\n" , (long) current->mm->end_data);
printk("(start_stack) %lx\n" , (long) current->mm->start_stack);
printk("(brk) %lx\n" , (long) current->mm->brk);
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 47362da04..b451332ed 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -70,39 +70,53 @@ ssize_t block_write(struct file * filp, const char * buf,
if (chars != blocksize)
fn = bread;
bh = fn(dev, block, blocksize);
+ if (!bh)
+ return written ? written : -EIO;
+ if (!buffer_uptodate(bh))
+ wait_on_buffer(bh);
}
#else
bh = getblk(dev, block, blocksize);
+ if (!bh)
+ return written ? written : -EIO;
- if (chars != blocksize && !buffer_uptodate(bh)) {
- if(!filp->f_reada ||
- !read_ahead[MAJOR(dev)]) {
- /* We do this to force the read of a single buffer */
- brelse(bh);
- bh = bread(dev,block,blocksize);
- } else {
- /* Read-ahead before write */
- blocks = read_ahead[MAJOR(dev)] / (blocksize >> 9) / 2;
- if (block + blocks > size) blocks = size - block;
- if (blocks > NBUF) blocks=NBUF;
+ if (!buffer_uptodate(bh))
+ {
+ if (chars == blocksize)
+ wait_on_buffer(bh);
+ else
+ {
bhlist[0] = bh;
- for(i=1; i<blocks; i++){
- bhlist[i] = getblk (dev, block+i, blocksize);
- if(!bhlist[i]){
- while(i >= 0) brelse(bhlist[i--]);
- return written ? written : -EIO;
- };
- };
+ if (!filp->f_reada || !read_ahead[MAJOR(dev)]) {
+ /* We do this to force the read of a single buffer */
+ blocks = 1;
+ } else {
+ /* Read-ahead before write */
+ blocks = read_ahead[MAJOR(dev)] / (blocksize >> 9) / 2;
+ if (block + blocks > size) blocks = size - block;
+ if (blocks > NBUF) blocks=NBUF;
+ if (!blocks) blocks = 1;
+ for(i=1; i<blocks; i++)
+ {
+ bhlist[i] = getblk (dev, block+i, blocksize);
+ if (!bhlist[i])
+ {
+ while(i >= 0) brelse(bhlist[i--]);
+ return written ? written : -EIO;
+ }
+ }
+ }
ll_rw_block(READ, blocks, bhlist);
for(i=1; i<blocks; i++) brelse(bhlist[i]);
wait_on_buffer(bh);
-
+ if (!buffer_uptodate(bh)) {
+ brelse(bh);
+ return written ? written : -EIO;
+ }
};
};
#endif
block++;
- if (!bh)
- return written ? written : -EIO;
p = offset + bh->b_data;
offset = 0;
*ppos += chars;
@@ -522,7 +536,7 @@ int check_disk_change(kdev_t dev)
if (sb && invalidate_inodes(sb))
printk("VFS: busy inodes on changed media.\n");
- invalidate_buffers(dev);
+ destroy_buffers(dev);
if (bdops->revalidate)
bdops->revalidate(dev);
diff --git a/fs/buffer.c b/fs/buffer.c
index b2bc7670f..9113c07cc 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -94,6 +94,7 @@ static struct bh_free_head free_list[NR_SIZES];
kmem_cache_t *bh_cachep;
static int grow_buffers(int size);
+static void __refile_buffer(struct buffer_head *);
/* This is used by some architectures to estimate available memory. */
atomic_t buffermem_pages = ATOMIC_INIT(0);
@@ -277,11 +278,14 @@ repeat:
void sync_dev(kdev_t dev)
{
- sync_buffers(dev, 0);
sync_supers(dev);
sync_inodes(dev);
- sync_buffers(dev, 0);
DQUOT_SYNC(dev);
+ /* sync all the dirty buffers out to disk only _after_ all the
+ high level layers finished generated buffer dirty data
+ (or we'll return with some buffer still dirty on the blockdevice
+ so breaking the semantics of this call) */
+ sync_buffers(dev, 0);
/*
* FIXME(eric) we need to sync the physical devices here.
* This is because some (scsi) controllers have huge amounts of
@@ -323,7 +327,9 @@ int file_fsync(struct file *filp, struct dentry *dentry)
struct inode * inode = dentry->d_inode;
struct super_block * sb;
kdev_t dev;
+ int ret;
+ lock_kernel();
/* sync the inode to buffers */
write_inode_now(inode);
@@ -335,7 +341,9 @@ int file_fsync(struct file *filp, struct dentry *dentry)
/* .. finally sync the buffers to disk */
dev = inode->i_dev;
- return sync_buffers(dev, 1);
+ ret = sync_buffers(dev, 1);
+ unlock_kernel();
+ return ret;
}
asmlinkage long sys_fsync(unsigned int fd)
@@ -345,7 +353,6 @@ asmlinkage long sys_fsync(unsigned int fd)
struct inode * inode;
int err;
- lock_kernel();
err = -EBADF;
file = fget(fd);
if (!file)
@@ -371,7 +378,6 @@ asmlinkage long sys_fsync(unsigned int fd)
out_putf:
fput(file);
out:
- unlock_kernel();
return err;
}
@@ -382,7 +388,6 @@ asmlinkage long sys_fdatasync(unsigned int fd)
struct inode * inode;
int err;
- lock_kernel();
err = -EBADF;
file = fget(fd);
if (!file)
@@ -408,44 +413,9 @@ asmlinkage long sys_fdatasync(unsigned int fd)
out_putf:
fput(file);
out:
- unlock_kernel();
return err;
}
-void invalidate_buffers(kdev_t dev)
-{
- int nlist;
-
- spin_lock(&lru_list_lock);
- for(nlist = 0; nlist < NR_LIST; nlist++) {
- struct buffer_head * bh;
- int i;
- retry:
- bh = lru_list[nlist];
- if (!bh)
- continue;
- for (i = nr_buffers_type[nlist]*2 ; --i > 0 ; bh = bh->b_next_free) {
- if (bh->b_dev != dev)
- continue;
- if (buffer_locked(bh)) {
- atomic_inc(&bh->b_count);
- spin_unlock(&lru_list_lock);
- wait_on_buffer(bh);
- spin_lock(&lru_list_lock);
- atomic_dec(&bh->b_count);
- goto retry;
- }
- if (atomic_read(&bh->b_count))
- continue;
- clear_bit(BH_Protected, &bh->b_state);
- clear_bit(BH_Uptodate, &bh->b_state);
- clear_bit(BH_Dirty, &bh->b_state);
- clear_bit(BH_Req, &bh->b_state);
- }
- }
- spin_unlock(&lru_list_lock);
-}
-
/* After several hours of tedious analysis, the following hash
* function won. Do not mess with it... -DaveM
*/
@@ -464,10 +434,12 @@ static __inline__ void __hash_link(struct buffer_head *bh, struct buffer_head **
static __inline__ void __hash_unlink(struct buffer_head *bh)
{
- if (bh->b_next)
- bh->b_next->b_pprev = bh->b_pprev;
- *(bh->b_pprev) = bh->b_next;
- bh->b_pprev = NULL;
+ if (bh->b_pprev) {
+ if (bh->b_next)
+ bh->b_next->b_pprev = bh->b_pprev;
+ *(bh->b_pprev) = bh->b_next;
+ bh->b_pprev = NULL;
+ }
}
static void __insert_into_lru_list(struct buffer_head * bh, int blist)
@@ -514,17 +486,12 @@ static void __remove_from_free_list(struct buffer_head * bh, int index)
bh->b_next_free = bh->b_prev_free = NULL;
}
-/* The following two functions must operate atomically
- * because they control the visibility of a buffer head
- * to the rest of the kernel.
- */
-static __inline__ void __remove_from_queues(struct buffer_head *bh)
+/* must be called with both the hash_table_lock and the lru_list_lock
+ held */
+static void __remove_from_queues(struct buffer_head *bh)
{
- write_lock(&hash_table_lock);
- if (bh->b_pprev)
- __hash_unlink(bh);
+ __hash_unlink(bh);
__remove_from_lru_list(bh, bh->b_list);
- write_unlock(&hash_table_lock);
}
static void insert_into_queues(struct buffer_head *bh)
@@ -547,6 +514,8 @@ static void put_last_free(struct buffer_head * bh)
struct bh_free_head *head = &free_list[BUFSIZE_INDEX(bh->b_size)];
struct buffer_head **bhp = &head->list;
+ bh->b_state = 0;
+
spin_lock(&head->lock);
bh->b_dev = B_FREE;
if(!*bhp) {
@@ -604,11 +573,73 @@ unsigned int get_hardblocksize(kdev_t dev)
return 0;
}
+/* If invalidate_buffers() will trash dirty buffers, it means some kind
+ of fs corruption is going on. Trashing dirty data always imply losing
+ information that was supposed to be just stored on the physical layer
+ by the user.
+
+ Thus invalidate_buffers in general usage is not allwowed to trash dirty
+ buffers. For example ioctl(FLSBLKBUF) expects dirty data to be preserved.
+
+ NOTE: In the case where the user removed a removable-media-disk even if
+ there's still dirty data not synced on disk (due a bug in the device driver
+ or due an error of the user), by not destroying the dirty buffers we could
+ generate corruption also on the next media inserted, thus a parameter is
+ necessary to handle this case in the most safe way possible (trying
+ to not corrupt also the new disk inserted with the data belonging to
+ the old now corrupted disk). Also for the ramdisk the natural thing
+ to do in order to release the ramdisk memory is to destroy dirty buffers.
+
+ These are two special cases. Normal usage imply the device driver
+ to issue a sync on the device (without waiting I/O completation) and
+ then an invalidate_buffers call that doesn't trashes dirty buffers. */
+void __invalidate_buffers(kdev_t dev, int destroy_dirty_buffers)
+{
+ int i, nlist, slept;
+ struct buffer_head * bh, * bh_next;
+
+ retry:
+ slept = 0;
+ spin_lock(&lru_list_lock);
+ for(nlist = 0; nlist < NR_LIST; nlist++) {
+ bh = lru_list[nlist];
+ if (!bh)
+ continue;
+ for (i = nr_buffers_type[nlist]; i > 0 ; bh = bh_next, i--) {
+ bh_next = bh->b_next_free;
+ if (bh->b_dev != dev)
+ continue;
+ if (buffer_locked(bh)) {
+ atomic_inc(&bh->b_count);
+ spin_unlock(&lru_list_lock);
+ wait_on_buffer(bh);
+ slept = 1;
+ spin_lock(&lru_list_lock);
+ atomic_dec(&bh->b_count);
+ }
+
+ write_lock(&hash_table_lock);
+ if (!atomic_read(&bh->b_count) &&
+ (destroy_dirty_buffers || !buffer_dirty(bh))) {
+ __remove_from_queues(bh);
+ put_last_free(bh);
+ }
+ write_unlock(&hash_table_lock);
+ if (slept)
+ goto out;
+ }
+ }
+out:
+ spin_unlock(&lru_list_lock);
+ if (slept)
+ goto retry;
+}
+
void set_blocksize(kdev_t dev, int size)
{
extern int *blksize_size[];
- int i, nlist;
- struct buffer_head * bh, *bhnext;
+ int i, nlist, slept;
+ struct buffer_head * bh, * bh_next;
if (!blksize_size[MAJOR(dev)])
return;
@@ -626,41 +657,53 @@ void set_blocksize(kdev_t dev, int size)
sync_buffers(dev, 2);
blksize_size[MAJOR(dev)][MINOR(dev)] = size;
- /* We need to be quite careful how we do this - we are moving entries
- * around on the free list, and we can get in a loop if we are not careful.
- */
+ retry:
+ slept = 0;
+ spin_lock(&lru_list_lock);
for(nlist = 0; nlist < NR_LIST; nlist++) {
- repeat:
- spin_lock(&lru_list_lock);
bh = lru_list[nlist];
- for (i = nr_buffers_type[nlist]*2 ; --i > 0 ; bh = bhnext) {
- if(!bh)
- break;
-
- bhnext = bh->b_next_free;
- if (bh->b_dev != dev)
- continue;
- if (bh->b_size == size)
- continue;
+ if (!bh)
+ continue;
+ for (i = nr_buffers_type[nlist]; i > 0 ; bh = bh_next, i--) {
+ bh_next = bh->b_next_free;
+ if (bh->b_dev != dev || bh->b_size == size)
+ continue;
if (buffer_locked(bh)) {
atomic_inc(&bh->b_count);
spin_unlock(&lru_list_lock);
wait_on_buffer(bh);
+ slept = 1;
+ spin_lock(&lru_list_lock);
atomic_dec(&bh->b_count);
- goto repeat;
- }
- if (bh->b_dev == dev && bh->b_size != size) {
- clear_bit(BH_Dirty, &bh->b_state);
- clear_bit(BH_Uptodate, &bh->b_state);
- clear_bit(BH_Req, &bh->b_state);
}
- if (atomic_read(&bh->b_count) == 0) {
+
+ write_lock(&hash_table_lock);
+ if (!atomic_read(&bh->b_count)) {
+ if (buffer_dirty(bh))
+ printk(KERN_WARNING
+ "set_blocksize: dev %s buffer_dirty %lu size %hu\n",
+ kdevname(dev), bh->b_blocknr, bh->b_size);
__remove_from_queues(bh);
put_last_free(bh);
+ } else {
+ if (atomic_set_buffer_clean(bh))
+ __refile_buffer(bh);
+ clear_bit(BH_Uptodate, &bh->b_state);
+ printk(KERN_WARNING
+ "set_blocksize: "
+ "b_count %d, dev %s, block %lu, from %p\n",
+ atomic_read(&bh->b_count), bdevname(bh->b_dev),
+ bh->b_blocknr, __builtin_return_address(0));
}
+ write_unlock(&hash_table_lock);
+ if (slept)
+ goto out;
}
- spin_unlock(&lru_list_lock);
}
+ out:
+ spin_unlock(&lru_list_lock);
+ if (slept)
+ goto retry;
}
/*
@@ -785,30 +828,31 @@ repeat:
atomic_set(&bh->b_count, 1);
}
spin_unlock(&free_list[isize].lock);
- if (!bh)
- goto refill;
- /* OK, FINALLY we know that this buffer is the only one of its kind,
- * we hold a reference (b_count>0), it is unlocked, and it is clean.
+ /*
+ * OK, FINALLY we know that this buffer is the only one of
+ * its kind, we hold a reference (b_count>0), it is unlocked,
+ * and it is clean.
*/
- init_buffer(bh, end_buffer_io_sync, NULL);
- bh->b_dev = dev;
- bh->b_blocknr = block;
- bh->b_state = 1 << BH_Mapped;
+ if (bh) {
+ init_buffer(bh, end_buffer_io_sync, NULL);
+ bh->b_dev = dev;
+ bh->b_blocknr = block;
+ bh->b_state = 1 << BH_Mapped;
- /* Insert the buffer into the regular lists */
- insert_into_queues(bh);
- goto out;
+ /* Insert the buffer into the regular lists */
+ insert_into_queues(bh);
+ out:
+ touch_buffer(bh);
+ return bh;
+ }
/*
* If we block while refilling the free list, somebody may
* create the buffer first ... search the hashes again.
*/
-refill:
refill_freelist(size);
goto repeat;
-out:
- return bh;
}
/* -1 -> no need to flush
@@ -820,11 +864,13 @@ static int balance_dirty_state(kdev_t dev)
dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT;
tot = nr_free_buffer_pages();
- hard_dirty_limit = tot * bdf_prm.b_un.nfract / 100;
- soft_dirty_limit = hard_dirty_limit >> 1;
+ tot -= size_buffers_type[BUF_PROTECTED] >> PAGE_SHIFT;
- if (dirty > soft_dirty_limit)
- {
+ dirty *= 200;
+ soft_dirty_limit = tot * bdf_prm.b_un.nfract;
+ hard_dirty_limit = soft_dirty_limit * 2;
+
+ if (dirty > soft_dirty_limit) {
if (dirty > hard_dirty_limit)
return 1;
return 0;
@@ -848,29 +894,39 @@ void balance_dirty(kdev_t dev)
wakeup_bdflush(state);
}
-static inline void __mark_dirty(struct buffer_head *bh, int flag)
+static __inline__ void __mark_dirty(struct buffer_head *bh, int flag)
{
bh->b_flushtime = jiffies + (flag ? bdf_prm.b_un.age_super : bdf_prm.b_un.age_buffer);
- clear_bit(BH_New, &bh->b_state);
refile_buffer(bh);
}
+/* atomic version, the user must call balance_dirty() by hand
+ as soon as it become possible to block */
void __mark_buffer_dirty(struct buffer_head *bh, int flag)
{
- __mark_dirty(bh, flag);
+ if (!atomic_set_buffer_dirty(bh))
+ __mark_dirty(bh, flag);
+}
+
+void mark_buffer_dirty(struct buffer_head *bh, int flag)
+{
+ __mark_buffer_dirty(bh, flag);
+ balance_dirty(bh->b_dev);
}
/*
* A buffer may need to be moved from one buffer list to another
* (e.g. in case it is not shared any more). Handle this.
*/
-static __inline__ void __refile_buffer(struct buffer_head *bh)
+static void __refile_buffer(struct buffer_head *bh)
{
int dispose = BUF_CLEAN;
if (buffer_locked(bh))
dispose = BUF_LOCKED;
if (buffer_dirty(bh))
dispose = BUF_DIRTY;
+ if (buffer_protected(bh))
+ dispose = BUF_PROTECTED;
if (dispose != bh->b_list) {
__remove_from_lru_list(bh, bh->b_list);
bh->b_list = dispose;
@@ -890,8 +946,6 @@ void refile_buffer(struct buffer_head *bh)
*/
void __brelse(struct buffer_head * buf)
{
- touch_buffer(buf);
-
if (atomic_read(&buf->b_count)) {
atomic_dec(&buf->b_count);
return;
@@ -912,12 +966,10 @@ void __bforget(struct buffer_head * buf)
write_lock(&hash_table_lock);
if (!atomic_dec_and_test(&buf->b_count) || buffer_locked(buf))
goto in_use;
- if (buf->b_pprev)
- __hash_unlink(buf);
+ __hash_unlink(buf);
write_unlock(&hash_table_lock);
__remove_from_lru_list(buf, buf->b_list);
spin_unlock(&lru_list_lock);
- buf->b_state = 0;
put_last_free(buf);
return;
@@ -1218,13 +1270,13 @@ static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], i
static void unmap_buffer(struct buffer_head * bh)
{
- if (buffer_mapped(bh))
- {
+ if (buffer_mapped(bh)) {
mark_buffer_clean(bh);
wait_on_buffer(bh);
clear_bit(BH_Uptodate, &bh->b_state);
clear_bit(BH_Mapped, &bh->b_state);
clear_bit(BH_Req, &bh->b_state);
+ clear_bit(BH_New, &bh->b_state);
}
}
@@ -1303,30 +1355,25 @@ static void create_empty_buffers(struct page *page, struct inode *inode, unsigne
static void unmap_underlying_metadata(struct buffer_head * bh)
{
-#if 0
- if (buffer_new(bh)) {
- struct buffer_head *old_bh;
-
- old_bh = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
- if (old_bh) {
- unmap_buffer(old_bh);
- /* Here we could run brelse or bforget. We use
- bforget because it will try to put the buffer
- in the freelist. */
- __bforget(old_bh);
- }
+ struct buffer_head *old_bh;
+
+ old_bh = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
+ if (old_bh) {
+ unmap_buffer(old_bh);
+ /* Here we could run brelse or bforget. We use
+ bforget because it will try to put the buffer
+ in the freelist. */
+ __bforget(old_bh);
}
-#endif
}
/*
* block_write_full_page() is SMP-safe - currently it's still
* being called with the kernel lock held, but the code is ready.
*/
-int block_write_full_page(struct dentry *dentry, struct page *page)
+static int __block_write_full_page(struct inode *inode, struct page *page, get_block_t *get_block)
{
- struct inode *inode = dentry->d_inode;
- int err, i;
+ int err, i, need_balance_dirty = 0;
unsigned long block;
struct buffer_head *bh, *head;
@@ -1337,17 +1384,11 @@ int block_write_full_page(struct dentry *dentry, struct page *page)
create_empty_buffers(page, inode, inode->i_sb->s_blocksize);
head = page->buffers;
- /* The page cache is now PAGE_CACHE_SIZE aligned, period. We handle old a.out
- * and others via unaligned private mappings.
- */
block = page->index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
bh = head;
i = 0;
do {
- if (!bh)
- BUG();
-
/*
* If the buffer isn't up-to-date, we can't be sure
* that the buffer has been initialized with the proper
@@ -1358,18 +1399,25 @@ int block_write_full_page(struct dentry *dentry, struct page *page)
*/
bh->b_end_io = end_buffer_io_sync;
if (!buffer_mapped(bh)) {
- err = inode->i_op->get_block(inode, block, bh, 1);
+ err = get_block(inode, block, bh, 1);
if (err)
goto out;
- unmap_underlying_metadata(bh);
+ if (buffer_new(bh))
+ unmap_underlying_metadata(bh);
}
set_bit(BH_Uptodate, &bh->b_state);
- mark_buffer_dirty(bh,0);
+ if (!atomic_set_buffer_dirty(bh)) {
+ __mark_dirty(bh, 0);
+ need_balance_dirty = 1;
+ }
bh = bh->b_this_page;
block++;
} while (bh != head);
+ if (need_balance_dirty)
+ balance_dirty(bh->b_dev);
+
SetPageUptodate(page);
return 0;
out:
@@ -1377,13 +1425,12 @@ out:
return err;
}
-int block_write_zero_range(struct inode *inode, struct page *page,
- unsigned zerofrom, unsigned from, unsigned to,
- const char * buf)
+static int __block_prepare_write(struct inode *inode, struct page *page,
+ unsigned from, unsigned to, get_block_t *get_block)
{
- unsigned zeroto = 0, block_start, block_end;
+ unsigned block_start, block_end;
unsigned long block;
- int err = 0, partial = 0, need_balance_dirty = 0;
+ int err = 0;
unsigned blocksize, bbits;
struct buffer_head *bh, *head, *wait[2], **wait_bh=wait;
char *kaddr = (char *)kmap(page);
@@ -1396,35 +1443,31 @@ int block_write_zero_range(struct inode *inode, struct page *page,
bbits = inode->i_sb->s_blocksize_bits;
block = page->index << (PAGE_CACHE_SHIFT - bbits);
- /*
- * First pass - map what needs to be mapped, initiate reads
- * on the boundaries if needed (i.e. if block is partially covered
- * _and_ is not up-to-date _and_ is not new).
- */
for(bh = head, block_start = 0; bh != head || !block_start;
block++, block_start=block_end, bh = bh->b_this_page) {
if (!bh)
BUG();
block_end = block_start+blocksize;
- if (block_end <= zerofrom)
+ if (block_end <= from)
continue;
if (block_start >= to)
break;
bh->b_end_io = end_buffer_io_sync;
if (!buffer_mapped(bh)) {
- err = inode->i_op->get_block(inode, block, bh, 1);
+ err = get_block(inode, block, bh, 1);
if (err)
goto out;
- unmap_underlying_metadata(bh);
- }
- if (buffer_new(bh)) {
- zeroto = block_end;
- if (block_start < zerofrom)
- zerofrom = block_start;
- continue;
+ if (buffer_new(bh)) {
+ unmap_underlying_metadata(bh);
+ if (block_end > to)
+ memset(kaddr+to, 0, block_end-to);
+ if (block_start < from)
+ memset(kaddr+block_start, 0, from-block_start);
+ continue;
+ }
}
if (!buffer_uptodate(bh) &&
- (block_start < zerofrom || block_end > to)) {
+ (block_start < from || block_end > to)) {
ll_rw_block(READ, 1, &bh);
*wait_bh++=bh;
}
@@ -1438,44 +1481,31 @@ int block_write_zero_range(struct inode *inode, struct page *page,
if (!buffer_uptodate(*wait_bh))
goto out;
}
- /*
- * Now we can copy the data.
- */
- if (zerofrom < from)
- memset(kaddr+zerofrom, 0, from-zerofrom);
- if (from < to)
- err = copy_from_user(kaddr+from, buf, to-from);
- if (to < zeroto)
- memset(kaddr+to, 0, zeroto-to);
- else
- zeroto = to;
- if (err < 0)
- goto out;
- /*
- * Second pass: check if all out-of-range blocks are up-to-date
- * and mark the rest up-to-date and dirty.
- *
- * NOTE! This also does a direct dirty balace check,
- * rather than relying on bdflush just waking up every
- * once in a while. This is to catch (and slow down)
- * the processes that write tons of buffer..
- *
- * Note how we do NOT want to do this in the full block
- * case: full pages are flushed not by the people who
- * dirtied them, but by people who need memory. And we
- * should not penalize them for somebody else writing
- * lots of dirty pages.
- */
- for(bh = head, block_start = 0;
+ return 0;
+out:
+ return err;
+}
+
+static int __block_commit_write(struct inode *inode, struct page *page,
+ unsigned from, unsigned to)
+{
+ unsigned block_start, block_end;
+ int partial = 0, need_balance_dirty = 0;
+ unsigned blocksize;
+ struct buffer_head *bh, *head;
+
+ blocksize = inode->i_sb->s_blocksize;
+
+ for(bh = head = page->buffers, block_start = 0;
bh != head || !block_start;
block_start=block_end, bh = bh->b_this_page) {
block_end = block_start + blocksize;
- if (block_end <= zerofrom || block_start >= zeroto) {
+ if (block_end <= from || block_start >= to) {
if (!buffer_uptodate(bh))
partial = 1;
} else {
set_bit(BH_Uptodate, &bh->b_state);
- if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
+ if (!atomic_set_buffer_dirty(bh)) {
__mark_dirty(bh, 0);
need_balance_dirty = 1;
}
@@ -1492,51 +1522,202 @@ int block_write_zero_range(struct inode *inode, struct page *page,
*/
if (!partial)
SetPageUptodate(page);
- kunmap(page);
return 0;
-out:
- ClearPageUptodate(page);
- kunmap(page);
- return err;
}
-int block_write_partial_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+/*
+ * Generic "read page" function for block devices that have the normal
+ * get_block functionality. This is most of the block device filesystems.
+ * Reads the page asynchronously --- the unlock_buffer() and
+ * mark_buffer_uptodate() functions propagate buffer state into the
+ * page struct once IO has completed.
+ */
+static inline int __block_read_full_page(struct inode *inode, struct page *page,
+ get_block_t *get_block)
{
- struct inode *inode = file->f_dentry->d_inode;
- int err;
+ unsigned long iblock;
+ struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
+ unsigned int blocksize, blocks;
+ unsigned long kaddr = 0;
+ int nr, i;
if (!PageLocked(page))
- BUG();
- if (offset < 0 || offset >= PAGE_SIZE)
- BUG();
- if (bytes+offset < 0 || bytes+offset > PAGE_SIZE)
- BUG();
+ PAGE_BUG(page);
+ blocksize = inode->i_sb->s_blocksize;
+ if (!page->buffers)
+ create_empty_buffers(page, inode, blocksize);
+ head = page->buffers;
- err = block_write_range(inode, page, offset, bytes, buf);
- return err ? err : bytes;
+ blocks = PAGE_CACHE_SIZE >> inode->i_sb->s_blocksize_bits;
+ iblock = page->index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
+ bh = head;
+ nr = 0;
+ i = 0;
+
+ do {
+ if (buffer_uptodate(bh))
+ continue;
+
+ if (!buffer_mapped(bh)) {
+ get_block(inode, iblock, bh, 0);
+ if (!buffer_mapped(bh)) {
+ if (!kaddr)
+ kaddr = kmap(page);
+ memset((char *)(kaddr + i*blocksize), 0, blocksize);
+ set_bit(BH_Uptodate, &bh->b_state);
+ continue;
+ }
+ }
+
+ init_buffer(bh, end_buffer_io_async, NULL);
+ atomic_inc(&bh->b_count);
+ arr[nr] = bh;
+ nr++;
+ } while (i++, iblock++, (bh = bh->b_this_page) != head);
+
+ ++current->maj_flt;
+ if (nr) {
+ if (Page_Uptodate(page))
+ BUG();
+ ll_rw_block(READ, nr, arr);
+ } else {
+ /*
+ * all buffers are uptodate - we can set the page
+ * uptodate as well.
+ */
+ SetPageUptodate(page);
+ UnlockPage(page);
+ }
+ if (kaddr)
+ kunmap(page);
+ return 0;
}
/*
* For moronic filesystems that do not allow holes in file.
- * we allow offset==PAGE_SIZE, bytes==0
+ * We may have to extend the file.
*/
-int block_write_cont_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+int cont_prepare_write(struct page *page, unsigned offset, unsigned to, get_block_t *get_block, unsigned long *bytes)
+{
+ struct address_space *mapping = page->mapping;
+ struct inode *inode = (struct inode*)mapping->host;
+ struct page *new_page;
+ unsigned long pgpos;
+ long status;
+ unsigned zerofrom;
+ unsigned blocksize = inode->i_sb->s_blocksize;
+ char *kaddr;
+
+ while(page->index > (pgpos = *bytes>>PAGE_CACHE_SHIFT)) {
+ status = -ENOMEM;
+ new_page = grab_cache_page(mapping, pgpos);
+ if (!new_page)
+ goto out;
+ /* we might sleep */
+ if (*bytes>>PAGE_CACHE_SHIFT != pgpos) {
+ UnlockPage(new_page);
+ page_cache_release(new_page);
+ continue;
+ }
+ zerofrom = *bytes & ~PAGE_CACHE_MASK;
+ if (zerofrom & (blocksize-1)) {
+ *bytes |= (blocksize-1);
+ (*bytes)++;
+ }
+ status = __block_prepare_write(inode, new_page, zerofrom,
+ PAGE_CACHE_SIZE, get_block);
+ if (status)
+ goto out_unmap;
+ kaddr = (char*)page_address(page);
+ memset(kaddr+zerofrom, 0, PAGE_CACHE_SIZE-zerofrom);
+ __block_commit_write(inode, new_page, zerofrom, to);
+ kunmap(new_page);
+ UnlockPage(new_page);
+ page_cache_release(new_page);
+ }
+
+ if (page->index < pgpos) {
+ /* completely inside the area */
+ zerofrom = offset;
+ } else {
+ /* page covers the boundary, find the boundary offset */
+ zerofrom = *bytes & ~PAGE_CACHE_MASK;
+
+ /* if we will expand the thing last block will be filled */
+ if (to > zerofrom && (zerofrom & (blocksize-1))) {
+ *bytes |= (blocksize-1);
+ (*bytes)++;
+ }
+
+ /* starting below the boundary? Nothing to zero out */
+ if (offset <= zerofrom)
+ zerofrom = offset;
+ }
+ status = __block_prepare_write(inode, page, zerofrom, to, get_block);
+ if (status)
+ goto out1;
+ kaddr = (char*)page_address(page);
+ if (zerofrom < offset) {
+ memset(kaddr+zerofrom, 0, offset-zerofrom);
+ __block_commit_write(inode, page, zerofrom, offset);
+ }
+ return 0;
+out1:
+ ClearPageUptodate(page);
+ kunmap(page);
+ return status;
+
+out_unmap:
+ ClearPageUptodate(new_page);
+ kunmap(new_page);
+ UnlockPage(new_page);
+ page_cache_release(new_page);
+out:
+ return status;
+}
+
+int block_prepare_write(struct page *page, unsigned from, unsigned to,
+ get_block_t *get_block)
{
- struct inode *inode = file->f_dentry->d_inode;
- int err;
- unsigned zerofrom = offset;
+ struct inode *inode = (struct inode*)page->mapping->host;
+ int err = __block_prepare_write(inode, page, from, to, get_block);
+ if (err) {
+ ClearPageUptodate(page);
+ kunmap(page);
+ }
+ return err;
+}
- if (page->index > (inode->i_size >> PAGE_CACHE_SHIFT))
- zerofrom = 0;
- else if (page->index == (inode->i_size >> PAGE_CACHE_SHIFT) &&
- offset > (inode->i_size & ~PAGE_CACHE_MASK))
- zerofrom = inode->i_size & ~PAGE_CACHE_MASK;
- err = block_write_zero_range(inode, page, zerofrom,offset,offset+bytes,
- buf);
- return err ? err : bytes;
+int generic_commit_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+{
+ __block_commit_write((struct inode*)page->mapping->host,page,from,to);
+ kunmap(page);
+ return 0;
}
+int block_write_full_page(struct page *page, get_block_t *get_block)
+{
+ struct inode *inode = (struct inode*)page->mapping->host;
+ return __block_write_full_page(inode, page, get_block);
+}
+
+int block_read_full_page(struct page *page, get_block_t *get_block)
+{
+ struct inode *inode = (struct inode*)page->mapping->host;
+ return __block_read_full_page(inode, page, get_block);
+}
+
+int generic_block_bmap(struct address_space *mapping, long block, get_block_t *get_block)
+{
+ struct buffer_head tmp;
+ struct inode *inode = (struct inode*)mapping->host;
+ tmp.b_state = 0;
+ tmp.b_blocknr = 0;
+ get_block(inode, block, &tmp, 0);
+ return tmp.b_blocknr;
+}
/*
* IO completion routine for a buffer_head being used for kiobuf IO: we
@@ -1814,93 +1995,22 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size)
return 0;
}
-/*
- * Generic "read page" function for block devices that have the normal
- * get_block functionality. This is most of the block device filesystems.
- * Reads the page asynchronously --- the unlock_buffer() and
- * mark_buffer_uptodate() functions propagate buffer state into the
- * page struct once IO has completed.
- */
-static inline int __block_read_full_page(struct inode *inode, struct page *page)
-{
- unsigned long iblock;
- struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
- unsigned int blocksize, blocks;
- unsigned long kaddr = 0;
- int nr, i;
-
- if (!PageLocked(page))
- PAGE_BUG(page);
- blocksize = inode->i_sb->s_blocksize;
- if (!page->buffers)
- create_empty_buffers(page, inode, blocksize);
- head = page->buffers;
-
- blocks = PAGE_CACHE_SIZE >> inode->i_sb->s_blocksize_bits;
- iblock = page->index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
- bh = head;
- nr = 0;
- i = 0;
-
- do {
- if (buffer_uptodate(bh))
- continue;
-
- if (!buffer_mapped(bh)) {
- inode->i_op->get_block(inode, iblock, bh, 0);
- if (!buffer_mapped(bh)) {
- if (!kaddr)
- kaddr = kmap(page);
- memset((char *)(kaddr + i*blocksize), 0, blocksize);
- set_bit(BH_Uptodate, &bh->b_state);
- continue;
- }
- }
-
- init_buffer(bh, end_buffer_io_async, NULL);
- atomic_inc(&bh->b_count);
- arr[nr] = bh;
- nr++;
- } while (i++, iblock++, (bh = bh->b_this_page) != head);
-
- ++current->maj_flt;
- if (nr) {
- if (Page_Uptodate(page))
- BUG();
- ll_rw_block(READ, nr, arr);
- } else {
- /*
- * all buffers are uptodate - we can set the page
- * uptodate as well.
- */
- SetPageUptodate(page);
- UnlockPage(page);
- }
- if (kaddr)
- kunmap(page);
- return 0;
-}
-
-int block_read_full_page(struct dentry *dentry, struct page *page)
-{
- return __block_read_full_page(dentry->d_inode, page);
-}
-
int block_symlink(struct inode *inode, const char *symname, int len)
{
- struct page *page = grab_cache_page(&inode->i_data, 0);
- mm_segment_t fs;
+ struct address_space *mapping = inode->i_mapping;
+ struct page *page = grab_cache_page(mapping, 0);
int err = -ENOMEM;
+ char *kaddr;
if (!page)
goto fail;
- fs = get_fs();
- set_fs(KERNEL_DS);
- err = block_write_range(inode, page, 0, len-1, symname);
- set_fs(fs);
- inode->i_size = len-1;
+ err = mapping->a_ops->prepare_write(page, 0, len-1);
if (err)
- goto fail_write;
+ goto fail_map;
+ kaddr = (char*)page_address(page);
+ memcpy(kaddr, symname, len-1);
+ mapping->a_ops->commit_write(NULL, page, 0, len-1);
+ inode->i_size = len-1;
/*
* Notice that we are _not_ going to block here - end of page is
* unmapped, so this will only try to map the rest of page, see
@@ -1908,14 +2018,15 @@ int block_symlink(struct inode *inode, const char *symname, int len)
* ->i_size will be enough for everything) and zero it out.
* OTOH it's obviously correct and should make the page up-to-date.
*/
- err = __block_read_full_page(inode, page);
+ err = mapping->a_ops->readpage(NULL, page);
wait_on_page(page);
page_cache_release(page);
if (err < 0)
goto fail;
mark_inode_dirty(inode);
return 0;
-fail_write:
+fail_map:
+ inode->i_size = len-1;
UnlockPage(page);
page_cache_release(page);
fail:
@@ -2000,7 +2111,7 @@ out:
*/
int try_to_free_buffers(struct page * page)
{
- struct buffer_head * tmp, * bh = page->buffers;
+ struct buffer_head * tmp, * p, * bh = page->buffers;
int index = BUFSIZE_INDEX(bh->b_size);
int ret;
@@ -2009,7 +2120,7 @@ int try_to_free_buffers(struct page * page)
spin_lock(&free_list[index].lock);
tmp = bh;
do {
- struct buffer_head * p = tmp;
+ p = tmp;
tmp = tmp->b_this_page;
if (buffer_busy(p))
@@ -2025,13 +2136,10 @@ int try_to_free_buffers(struct page * page)
/* The buffer can be either on the regular
* queues or on the free list..
*/
- if (p->b_dev == B_FREE) {
+ if (p->b_dev != B_FREE)
+ __remove_from_queues(p);
+ else
__remove_from_free_list(p, index);
- } else {
- if (p->b_pprev)
- __hash_unlink(p);
- __remove_from_lru_list(p, p->b_list);
- }
__put_unused_buffer_head(p);
} while (tmp != bh);
spin_unlock(&unused_list_lock);
@@ -2051,7 +2159,8 @@ out:
busy_buffer_page:
/* Uhhuh, start writeback so that we don't end up with all dirty pages */
- wakeup_bdflush(0);
+ if (buffer_dirty(p))
+ wakeup_bdflush(0);
ret = 0;
goto out;
}
@@ -2065,7 +2174,7 @@ void show_buffers(void)
int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;
int protected = 0;
int nlist;
- static char *buf_types[NR_LIST] = { "CLEAN", "LOCKED", "DIRTY" };
+ static char *buf_types[NR_LIST] = { "CLEAN", "LOCKED", "DIRTY", "PROTECTED", };
#endif
printk("Buffer memory: %6dkB\n",
@@ -2091,10 +2200,16 @@ void show_buffers(void)
used++, lastused = found;
bh = bh->b_next_free;
} while (bh != lru_list[nlist]);
- printk("%8s: %d buffers, %d used (last=%d), "
+ {
+ int tmp = nr_buffers_type[nlist];
+ if (found != tmp)
+ printk("%9s: BUG -> found %d, reported %d\n",
+ buf_types[nlist], found, tmp);
+ }
+ printk("%9s: %d buffers, %lu kbyte, %d used (last=%d), "
"%d locked, %d protected, %d dirty\n",
- buf_types[nlist], found, used, lastused,
- locked, protected, dirty);
+ buf_types[nlist], found, size_buffers_type[nlist]>>10,
+ used, lastused, locked, protected, dirty);
}
spin_unlock(&lru_list_lock);
#endif
@@ -2184,8 +2299,7 @@ void wakeup_bdflush(int block)
if (current == bdflush_tsk)
return;
- if (!block)
- {
+ if (!block) {
wake_up_process(bdflush_tsk);
return;
}
@@ -2210,7 +2324,7 @@ void wakeup_bdflush(int block)
as all dirty buffers lives _only_ in the DIRTY lru list.
As we never browse the LOCKED and CLEAN lru lists they are infact
completly useless. */
-static void flush_dirty_buffers(int check_flushtime)
+static int flush_dirty_buffers(int check_flushtime)
{
struct buffer_head * bh, *next;
int flushed = 0, i;
@@ -2220,29 +2334,24 @@ static void flush_dirty_buffers(int check_flushtime)
bh = lru_list[BUF_DIRTY];
if (!bh)
goto out_unlock;
- for (i = nr_buffers_type[BUF_DIRTY]; i-- > 0; bh = next)
- {
+ for (i = nr_buffers_type[BUF_DIRTY]; i-- > 0; bh = next) {
next = bh->b_next_free;
- if (!buffer_dirty(bh))
- {
+ if (!buffer_dirty(bh)) {
__refile_buffer(bh);
continue;
}
if (buffer_locked(bh))
continue;
- if (check_flushtime)
- {
- /* The dirty lru list is chronogical ordered so
+ if (check_flushtime) {
+ /* The dirty lru list is chronologically ordered so
if the current bh is not yet timed out,
then also all the following bhs
will be too young. */
if (time_before(jiffies, bh->b_flushtime))
goto out_unlock;
- }
- else
- {
+ } else {
if (++flushed > bdf_prm.b_un.ndirty)
goto out_unlock;
}
@@ -2259,6 +2368,8 @@ static void flush_dirty_buffers(int check_flushtime)
}
out_unlock:
spin_unlock(&lru_list_lock);
+
+ return flushed;
}
/*
@@ -2342,6 +2453,7 @@ asmlinkage long sys_bdflush(int func, long data)
*/
int bdflush(void * unused)
{
+ int flushed;
/*
* We have a bare-bones task_struct, and really should fill
* in a few more things so "top" and /proc/2/{exe,root,cwd}
@@ -2363,7 +2475,7 @@ int bdflush(void * unused)
for (;;) {
CHECK_EMERGENCY_SYNC
- flush_dirty_buffers(0);
+ flushed = flush_dirty_buffers(0);
/* If wakeup_bdflush will wakeup us
after our bdflush_done wakeup, then
@@ -2378,10 +2490,10 @@ int bdflush(void * unused)
/*
* If there are still a lot of dirty buffers around,
* skip the sleep and flush some more. Otherwise, we
- * sleep for a while.
+ * go to sleep waiting a wakeup.
*/
- if (balance_dirty_state(NODEV) < 0)
- schedule_timeout(5*HZ);
+ if (!flushed || balance_dirty_state(NODEV) < 0)
+ schedule();
/* Remember to mark us as running otherwise
the next schedule will block. */
__set_current_state(TASK_RUNNING);
@@ -2413,24 +2525,19 @@ int kupdate(void * unused)
for (;;) {
/* update interval */
interval = bdf_prm.b_un.interval;
- if (interval)
- {
+ if (interval) {
tsk->state = TASK_INTERRUPTIBLE;
schedule_timeout(interval);
- }
- else
- {
+ } else {
stop_kupdate:
tsk->state = TASK_STOPPED;
schedule(); /* wait for SIGCONT */
}
/* check for sigstop */
- if (signal_pending(tsk))
- {
+ if (signal_pending(tsk)) {
int stopped = 0;
spin_lock_irq(&tsk->sigmask_lock);
- if (sigismember(&tsk->signal, SIGSTOP))
- {
+ if (sigismember(&tsk->signal, SIGSTOP)) {
sigdelset(&tsk->signal, SIGSTOP);
stopped = 1;
}
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index faa983e0f..88e954eeb 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -39,12 +39,62 @@ static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
inode->i_op = &coda_file_inode_operations;
else if (S_ISDIR(inode->i_mode))
inode->i_op = &coda_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &coda_symlink_inode_operations;
- else
+ else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_data.a_ops = &coda_symlink_aops;
+ } else
init_special_inode(inode, inode->i_mode, attr->va_rdev);
}
+struct inode * coda_iget(struct super_block * sb, ViceFid * fid,
+ struct coda_vattr * attr)
+{
+ struct inode *inode;
+ struct coda_sb_info *sbi= coda_sbp(sb);
+ struct coda_inode_info *cii;
+ ino_t ino = attr->va_fileid;
+
+ inode = iget(sb, ino);
+ if ( !inode ) {
+ CDEBUG(D_CNODE, "coda_iget: no inode\n");
+ return NULL;
+ }
+
+ /* check if the inode is already initialized */
+ cii = ITOC(inode);
+ if (cii->c_magic == CODA_CNODE_MAGIC)
+ goto out;
+
+ /* Initialize the Coda inode info structure */
+ memset(cii, 0, (int) sizeof(struct coda_inode_info));
+ cii->c_magic = CODA_CNODE_MAGIC;
+ cii->c_fid = *fid;
+ cii->c_flags = 0;
+ cii->c_vnode = inode;
+ INIT_LIST_HEAD(&(cii->c_cnhead));
+ INIT_LIST_HEAD(&(cii->c_volrootlist));
+
+ coda_fill_inode(inode, attr);
+
+ /* check if it is a weird fid (hashed fid != ino), f.i mountpoints
+ repair object, expanded local-global conflict trees, etc.
+ */
+ if ( coda_f2i(fid) == ino )
+ goto out;
+
+ /* check if we expect this weird fid */
+ if ( !coda_fid_is_weird(fid) )
+ printk("Coda: unknown weird fid: ino %ld, fid %s."
+ "Tell Peter.\n", (long)ino, coda_f2s(&cii->c_fid));
+
+ /* add the inode to a global list so we can find it back later */
+ list_add(&cii->c_volrootlist, &sbi->sbi_volroothead);
+ CDEBUG(D_CNODE, "Added %ld, %s to volroothead\n",
+ (long)ino, coda_f2s(&cii->c_fid));
+out:
+ return inode;
+}
+
/* this is effectively coda_iget:
- get attributes (might be cached)
- get the inode for the fid using vfs iget
@@ -54,16 +104,12 @@ static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
{
struct coda_inode_info *cnp;
- struct coda_sb_info *sbi= coda_sbp(sb);
struct coda_vattr attr;
int error;
- ino_t ino;
ENTRY;
- /*
- * We get inode numbers from Venus -- see venus source
- */
+ /* We get inode numbers from Venus -- see venus source */
error = venus_getattr(sb, fid, &attr);
if ( error ) {
@@ -74,53 +120,29 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
return error;
}
- ino = attr.va_fileid;
- *inode = iget(sb, ino);
- if ( !*inode ) {
- printk("coda_cnode_make: iget failed\n");
+ *inode = coda_iget(sb, fid, &attr);
+ if ( !(*inode) ) {
+ printk("coda_cnode_make: coda_iget failed\n");
return -ENOMEM;
}
cnp = ITOC(*inode);
- /* see if we've got it already */
- if ( cnp->c_magic != 0 && coda_fideq(fid, &cnp->c_fid)) {
+ /* see if it is the right one (we might have an inode collision) */
+ if ( coda_fideq(fid, &cnp->c_fid) ) {
+ CDEBUG(D_DOWNCALL,
+ "Done making inode: ino %ld, count %d with %s\n",
+ (*inode)->i_ino, (*inode)->i_count,
+ coda_f2s(&cnp->c_fid));
+ EXIT;
return 0;
}
- /* not fresh: collision */
- if ( cnp->c_magic != 0 ) {
- printk("coda_cnode_make on initialized inode %ld, old %s new
-%s!\n",
+ /* collision */
+ printk("coda_cnode_make on initialized inode %ld, old %s new %s!\n",
(*inode)->i_ino, coda_f2s(&cnp->c_fid), coda_f2s2(fid));
iput(*inode);
- return -ENOENT;
- }
-
- memset(cnp, 0, (int) sizeof(struct coda_inode_info));
- cnp->c_fid = *fid;
- cnp->c_magic = CODA_CNODE_MAGIC;
- cnp->c_flags = 0;
- cnp->c_vnode = *inode;
- INIT_LIST_HEAD(&(cnp->c_cnhead));
- INIT_LIST_HEAD(&(cnp->c_volrootlist));
-
- /* fill in the inode attributes */
- if ( coda_f2i(fid) != ino ) {
- if ( !coda_fid_is_weird(fid) )
- printk("Coda: unknown weird fid: ino %ld, fid %s."
- "Tell Peter.\n", (long)ino, coda_f2s(&cnp->c_fid));
- list_add(&cnp->c_volrootlist, &sbi->sbi_volroothead);
- CDEBUG(D_UPCALL, "Added %ld ,%s to volroothead\n",
- (long)ino, coda_f2s(&cnp->c_fid));
- }
-
- coda_fill_inode(*inode, &attr);
- CDEBUG(D_DOWNCALL, "Done making inode: ino %ld, count %d with %s\n",
- (*inode)->i_ino, (*inode)->i_count,
- coda_f2s(&cnp->c_fid));
-
EXIT;
- return 0;
+ return -ENOENT;
}
@@ -183,11 +205,13 @@ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
coda_f2s(&cii->c_fid), cii->c_vnode->i_ino);
if ( coda_fideq(&cii->c_fid, fid) ) {
inode = cii->c_vnode;
- CDEBUG(D_INODE, "volume root, found %ld\n", cii->c_vnode->i_ino);
+ CDEBUG(D_INODE, "volume root, found %ld\n", inode->i_ino);
if ( cii->c_magic != CODA_CNODE_MAGIC )
printk("%s: Bad magic in inode, tell Peter.\n",
__FUNCTION__);
- return cii->c_vnode;
+
+ iget(sb, inode->i_ino);
+ return inode;
}
}
@@ -224,7 +248,6 @@ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
}
CDEBUG(D_INODE, "found %ld\n", inode->i_ino);
- iput(inode);
return inode;
}
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
index 5f2f3c467..4a7bebb62 100644
--- a/fs/coda/coda_linux.c
+++ b/fs/coda/coda_linux.c
@@ -102,7 +102,6 @@ int coda_fid_is_weird(struct ViceFid *fid)
return 1;
return 0;
-
}
@@ -290,7 +289,6 @@ void coda_iattr_to_vattr(struct iattr *iattr, struct coda_vattr *vattr)
vattr->va_ctime.tv_sec = iattr->ia_ctime;
vattr->va_ctime.tv_nsec = 0;
}
-
}
void print_vattr(struct coda_vattr *attr)
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 2a1a122c8..3eecd4a5a 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -77,26 +77,16 @@ struct inode_operations coda_dir_inode_operations =
coda_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
NULL, /* truncate */
coda_permission, /* permission */
coda_revalidate_inode /* revalidate */
};
struct file_operations coda_dir_operations = {
- NULL, /* lseek */
- NULL, /* read -- bad */
- NULL, /* write */
- coda_readdir, /* readdir */
- NULL, /* select */
- NULL, /* ioctl */
- NULL, /* mmap */
- coda_open, /* open */
- NULL,
- coda_release, /* release */
- coda_fsync, /* fsync */
+ readdir: coda_readdir,
+ open: coda_open,
+ release: coda_release,
+ fsync: coda_fsync,
};
@@ -206,7 +196,6 @@ int coda_permission(struct inode *inode, int mask)
}
-
/* creation routines: create, mknod, mkdir, link, symlink */
static int coda_create(struct inode *dir, struct dentry *de, int mode)
@@ -267,7 +256,8 @@ static int coda_mknod(struct inode *dir, struct dentry *de, int mode, int rdev)
coda_vfs_stat.create++;
- CDEBUG(D_INODE, "name: %s, length %d, mode %o, rdev %x\n",name, length, mode, rdev);
+ CDEBUG(D_INODE, "name: %s, length %d, mode %o, rdev %x\n",
+ name, length, mode, rdev);
if (coda_isroot(dir) && coda_iscontrol(name, length))
return -EPERM;
@@ -528,7 +518,6 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
}
-
/* file operations for directories */
int coda_readdir(struct file *file, void *dirent, filldir_t filldir)
{
@@ -607,11 +596,11 @@ int coda_open(struct inode *i, struct file *f)
coda_load_creds(cred);
f->private_data = cred;
- if ( cnp->c_ovp ) {
+ if ( cnp->c_ovp )
iput(cnp->c_ovp);
- cnp->c_ovp = NULL;
- }
+
cnp->c_ovp = cont_inode;
+ i->i_mapping = cont_inode->i_mapping;
cnp->c_ocount++;
CDEBUG(D_FILE, "result %d, coda i->i_count is %d for ino %ld\n",
@@ -626,7 +615,7 @@ int coda_open(struct inode *i, struct file *f)
int coda_release(struct inode *i, struct file *f)
{
struct coda_inode_info *cnp;
- int error;
+ int error = 0;
unsigned short flags = (f->f_flags) & (~O_EXCL);
unsigned short cflags = coda_flags_to_cflags(flags);
struct coda_cred *cred;
@@ -652,14 +641,17 @@ int coda_release(struct inode *i, struct file *f)
--cnp->c_ocount;
- if (flags & (O_WRONLY | O_RDWR)) {
+ if ( flags & (O_WRONLY | O_RDWR) )
--cnp->c_owrite;
- }
+ /* Venus closing a container file? don't bother making the upcall. */
+ if ( current->pid != coda_upc_comm.vc_pid ) {
error = venus_release(i->i_sb, &(cnp->c_fid), cflags, cred);
+ }
- CODA_FREE(cred, sizeof(*cred));
f->private_data = NULL;
+ if (cred)
+ CODA_FREE(cred, sizeof(*cred));
CDEBUG(D_FILE, "coda_release: result: %d\n", error);
return error;
@@ -857,19 +849,18 @@ int coda_revalidate_inode(struct dentry *dentry)
if ( cii->c_flags == 0 )
return 0;
- /* Venus closed the device .... */
- if ( cii->c_flags & C_DYING ) {
- make_bad_inode(inode);
- return -EIO;
- }
+ /* Venus accessing a container file, don't try to revalidate */
+ if ( current->pid == coda_upc_comm.vc_pid )
+ return 0;
+ /* Venus closed the device .... */
+ if ( cii->c_flags & C_DYING )
+ goto return_bad_inode;
if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
- if ( error ) {
- make_bad_inode(inode);
- return -EIO;
- }
+ if ( error )
+ goto return_bad_inode;
/* this inode may be lost if:
- it's ino changed
@@ -887,12 +878,9 @@ int coda_revalidate_inode(struct dentry *dentry)
}
/* the following can happen when a local fid is replaced
- with a global one, here we lose and declar the inode bad */
- if (inode->i_ino != old_ino) {
- make_bad_inode(inode);
- inode->i_mode = old_mode;
- return -EIO;
- }
+ with a global one, here we lose and declare the inode bad */
+ if (inode->i_ino != old_ino)
+ goto return_bad_inode;
if ( cii->c_flags )
coda_flag_inode_children(inode, C_FLUSH);
@@ -901,5 +889,14 @@ int coda_revalidate_inode(struct dentry *dentry)
}
return 0;
+
+return_bad_inode:
+ if ( cii->c_ovp ) {
+ iput(cii->c_ovp);
+ inode->i_mapping = &inode->i_data;
+ cii->c_ovp = NULL;
+ }
+ make_bad_inode(inode);
+ return -EIO;
}
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 726bd18fd..82f661111 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -14,6 +14,7 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/locks.h>
+#include <linux/smp_lock.h>
#include <asm/segment.h>
#include <linux/string.h>
#include <asm/uaccess.h>
@@ -26,9 +27,6 @@
#include <linux/coda_proc.h>
/* file operations */
-static int coda_readpage(struct dentry *dentry, struct page * page);
-static ssize_t coda_file_read(struct file *f, char *buf, size_t count, loff_t *off);
-static ssize_t coda_file_write(struct file *f, const char *buf, size_t count, loff_t *off);
static int coda_file_mmap(struct file * file, struct vm_area_struct * vma);
/* also exported from this file (used for dirs) */
@@ -47,57 +45,21 @@ struct inode_operations coda_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* get_block */
- coda_readpage, /* readpage */
- NULL, /* writepage */
NULL, /* truncate */
coda_permission, /* permission */
coda_revalidate_inode /* revalidate */
};
struct file_operations coda_file_operations = {
- NULL, /* lseek - default should work for coda */
- coda_file_read, /* read */
- coda_file_write, /* write */
- NULL, /* readdir */
- NULL, /* select - default */
- NULL, /* ioctl */
- coda_file_mmap, /* mmap */
- coda_open, /* open */
- NULL,
- coda_release, /* release */
- coda_fsync, /* fsync */
- NULL, /* fasync */
- NULL /* lock */
+ read: generic_file_read,
+ write: generic_file_write,
+ mmap: coda_file_mmap,
+ open: coda_open,
+ release: coda_release,
+ fsync: coda_fsync,
};
-
-/* File file operations */
-static int coda_readpage(struct dentry * dentry, struct page * page)
-{
- struct inode *coda_inode = dentry->d_inode;
- struct dentry cont_dentry;
- struct coda_inode_info *cii;
-
- ENTRY;
- coda_vfs_stat.readpage++;
-
- cii = ITOC(coda_inode);
-
- if ( ! cii->c_ovp ) {
- printk("coda_readpage: no open inode for ino %ld, %s\n",
- coda_inode->i_ino, dentry->d_name.name);
- return -ENXIO;
- }
-
- cont_dentry.d_inode = cii->c_ovp;
-
- CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n",
- coda_inode->i_ino, cii->c_ovp->i_ino, page->index);
-
- block_read_full_page(&cont_dentry, page);
- EXIT;
- return 0;
-}
+
+/* File operations */
static int coda_file_mmap(struct file * file, struct vm_area_struct * vma)
{
@@ -115,89 +77,6 @@ static int coda_file_mmap(struct file * file, struct vm_area_struct * vma)
return res;
}
-static ssize_t coda_file_read(struct file *coda_file, char *buff,
- size_t count, loff_t *ppos)
-{
- struct coda_inode_info *cnp;
- struct inode *coda_inode = coda_file->f_dentry->d_inode;
- struct inode *cont_inode = NULL;
- struct file cont_file;
- struct dentry cont_dentry;
- int result = 0;
-
- ENTRY;
- coda_vfs_stat.file_read++;
-
- cnp = ITOC(coda_inode);
- CHECK_CNODE(cnp);
-
- cont_inode = cnp->c_ovp;
- if ( cont_inode == NULL ) {
- printk("coda_file_read: cached inode is 0!\n");
- return -1;
- }
-
- coda_prepare_openfile(coda_inode, coda_file, cont_inode,
- &cont_file, &cont_dentry);
-
- if (!cont_file.f_op || ! cont_file.f_op->read) {
- printk( "container file has no read in file operations.\n");
- return -1;
- }
-
- result = cont_file.f_op->read(&cont_file , buff, count,
- &(cont_file.f_pos));
-
- CDEBUG(D_FILE, "ops at %p result %d, count %ld, position: %d\n",
- cont_file.f_op, result, (long)count, (int)cont_file.f_pos);
-
- coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file);
- return result;
-}
-
-
-static ssize_t coda_file_write(struct file *coda_file, const char *buff,
- size_t count, loff_t *ppos)
-{
- struct coda_inode_info *cnp;
- struct inode *coda_inode = coda_file->f_dentry->d_inode;
- struct inode *cont_inode = NULL;
- struct file cont_file;
- struct dentry cont_dentry;
- int result = 0;
-
- ENTRY;
- coda_vfs_stat.file_write++;
-
- cnp = ITOC(coda_inode);
- CHECK_CNODE(cnp);
-
- cont_inode = cnp->c_ovp;
- if ( cont_inode == NULL ) {
- printk("coda_file_write: cached inode is 0!\n");
- return -1;
- }
-
- coda_prepare_openfile(coda_inode, coda_file, cont_inode,
- &cont_file, &cont_dentry);
-
- if (!cont_file.f_op || !cont_file.f_op->write) {
- printk("coda_file_write: container file has no file ops.\n");
- return -1;
- }
-
- down(&cont_inode->i_sem);
- result = cont_file.f_op->write(&cont_file , buff, count,
- &(cont_file.f_pos));
- up(&cont_inode->i_sem);
- coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file);
-
- if (result)
- cnp->c_flags |= C_VATTR;
-
- return result;
-}
-
int coda_fsync(struct file *coda_file, struct dentry *coda_dentry)
{
struct coda_inode_info *cnp;
@@ -213,12 +92,14 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry)
S_ISLNK(coda_inode->i_mode)))
return -EINVAL;
+ lock_kernel();
cnp = ITOC(coda_inode);
CHECK_CNODE(cnp);
cont_inode = cnp->c_ovp;
if ( cont_inode == NULL ) {
printk("coda_file_write: cached inode is 0!\n");
+ unlock_kernel();
return -1;
}
@@ -235,6 +116,7 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry)
up(&cont_inode->i_sem);
coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file);
+ unlock_kernel();
return result;
}
/*
@@ -284,8 +166,8 @@ int coda_inode_grab(dev_t dev, ino_t ino, struct inode **ind)
*ind = iget(sbptr, ino);
if ( *ind == NULL ) {
- printk("coda_inode_grab: iget(dev: %d, ino: %ld)
- returns NULL.\n", dev, (long)ino);
+ printk("coda_inode_grab: iget(dev: %d, ino: %ld) "
+ "returns NULL.\n", dev, (long)ino);
return -ENOENT;
}
CDEBUG(D_FILE, "ino: %ld, ops at %p\n", (long)ino, (*ind)->i_op);
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index e2f2931b1..b389b623e 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -52,7 +52,9 @@ struct super_operations coda_super_operations =
coda_put_super, /* put_super */
NULL, /* write_super */
coda_statfs, /* statfs */
- NULL /* remount_fs */
+ NULL, /* remount_fs */
+ NULL, /* no clear inode */
+ NULL /* umount attempt begin */
};
static struct super_block * coda_read_super(struct super_block *sb,
@@ -163,15 +165,16 @@ static void coda_read_inode(struct inode *inode)
return;
}
-static void coda_put_inode(struct inode *in)
+static void coda_put_inode(struct inode *inode)
{
ENTRY;
- CDEBUG(D_INODE,"ino: %ld, count %d\n", in->i_ino, in->i_count);
-
- if ( in->i_count == 1 )
- in->i_nlink = 0;
+ CDEBUG(D_INODE,"ino: %ld, count %d\n", inode->i_ino, inode->i_count);
+ if ( inode->i_count == 1 ) {
+ write_inode_now(inode);
+ inode->i_nlink = 0;
+ }
}
static void coda_delete_inode(struct inode *inode)
@@ -189,15 +192,17 @@ static void coda_delete_inode(struct inode *inode)
return;
}
-
- if ( ! list_empty(&cii->c_volrootlist) )
+ if ( ! list_empty(&cii->c_volrootlist) ) {
list_del(&cii->c_volrootlist);
+ INIT_LIST_HEAD(&cii->c_volrootlist);
+ }
open_inode = cii->c_ovp;
if ( open_inode ) {
CDEBUG(D_SUPER, "DELINO cached file: ino %ld count %d.\n",
open_inode->i_ino, open_inode->i_count);
cii->c_ovp = NULL;
+ inode->i_mapping = &inode->i_data;
iput(open_inode);
}
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index cec92b7f4..9a900a91a 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -46,26 +46,15 @@ struct inode_operations coda_ioctl_inode_operations =
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
NULL, /* truncate */
coda_ioctl_permission, /* permission */
NULL /* revalidate */
};
struct file_operations coda_ioctl_operations = {
- NULL, /* lseek - default should work for coda */
- NULL, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* select - default */
- coda_pioctl, /* ioctl */
- NULL, /* mmap */
- coda_ioctl_open, /* open */
- NULL,
- coda_ioctl_release, /* release */
- NULL, /* fsync */
+ ioctl: coda_pioctl,
+ open: coda_ioctl_open,
+ release: coda_ioctl_release,
};
/* the coda pioctl inode ops */
@@ -79,7 +68,6 @@ static int coda_ioctl_permission(struct inode *inode, int mask)
/* The pioctl file ops*/
int coda_ioctl_open(struct inode *i, struct file *f)
{
-
ENTRY;
CDEBUG(D_PIOCTL, "File inode number: %ld\n",
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index 65aeee08e..07ba22335 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -76,6 +76,21 @@ static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
return mask;
}
+static int coda_psdev_ioctl(struct inode * inode, struct file * filp,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned int data;
+
+ switch(cmd) {
+ case CIOC_KERNEL_VERSION:
+ data = CODA_KERNEL_VERSION;
+ return put_user(data, (int *) arg);
+ default:
+ return -ENOTTY;
+ }
+
+ return 0;
+}
/*
* Receive a message written by Venus to the psdev
@@ -246,7 +261,6 @@ static int coda_psdev_open(struct inode * inode, struct file * file)
vcp->vc_inuse++;
MOD_INC_USE_COUNT;
-
if ( file->f_flags == O_RDWR ) {
vcp->vc_pid = current->pid;
vcp->vc_seq = 0;
@@ -262,7 +276,6 @@ static int coda_psdev_open(struct inode * inode, struct file * file)
}
-
static int coda_psdev_release(struct inode * inode, struct file * file)
{
struct venus_comm *vcp = &coda_upc_comm;
@@ -298,6 +311,7 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
CODA_FREE(req, (u_int)sizeof(struct upc_req));
continue;
}
+ req->uc_flags |= REQ_ABORT;
wake_up(&req->uc_sleep);
}
@@ -305,6 +319,7 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
CDEBUG(D_PSDEV, "wake up processing clients\n");
while ( (lh = lh->next) != &vcp->vc_processing) {
req = list_entry(lh, struct upc_req, uc_chain);
+ req->uc_flags |= REQ_ABORT;
wake_up(&req->uc_sleep);
}
CDEBUG(D_PSDEV, "Done.\n");
@@ -315,19 +330,12 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
static struct file_operations coda_psdev_fops = {
- NULL, /* llseek */
- coda_psdev_read, /* read */
- coda_psdev_write, /* write */
- NULL, /* coda_psdev_readdir */
- coda_psdev_poll, /* poll */
- NULL, /* ioctl */
- NULL, /* coda_psdev_mmap */
- coda_psdev_open, /* open */
- NULL,
- coda_psdev_release, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
- NULL /* lock */
+ read: coda_psdev_read,
+ write: coda_psdev_write,
+ poll: coda_psdev_poll,
+ ioctl: coda_psdev_ioctl,
+ open: coda_psdev_open,
+ release: coda_psdev_release,
};
diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c
index 872370cf9..d44d0f7c3 100644
--- a/fs/coda/symlink.c
+++ b/fs/coda/symlink.c
@@ -48,8 +48,6 @@ fail:
return error;
}
-struct inode_operations coda_symlink_inode_operations = {
- readlink: page_readlink,
- follow_link: page_follow_link,
+struct address_space_operations coda_symlink_aops = {
readpage: coda_symlink_filler
};
diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c
index 046153362..289f9417c 100644
--- a/fs/coda/sysctl.c
+++ b/fs/coda/sysctl.c
@@ -109,7 +109,8 @@ char *coda_upcall_names[] = {
"open_by_path", /* 31 */
"resolve ", /* 32 */
"reintegrate ", /* 33 */
- "statfs " /* 34 */
+ "statfs ", /* 34 */
+ "make_cinode " /* 35 */
};
@@ -214,8 +215,8 @@ unsigned long get_time_std_deviation( const struct coda_upcall_stats_entry * pen
return 0;
time_avg = get_time_average( pentry );
- return
- sqr_root( (pentry->time_squared_sum / pentry->count) -
+
+ return sqr_root( (pentry->time_squared_sum / pentry->count) -
time_avg * time_avg );
}
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 9aecd8a6e..63586d05c 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -24,6 +24,7 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/locks.h>
@@ -392,7 +393,7 @@ int venus_readlink(struct super_block *sb, struct ViceFid *fid,
if ( retlen > *length )
retlen = *length;
*length = retlen;
- result = (char *)outp + (int)outp->coda_readlink.data;
+ result = (char *)outp + (long)outp->coda_readlink.data;
memcpy(buffer, result, retlen);
*(buffer + retlen) = '\0';
}
@@ -541,7 +542,7 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
/* get the data out of user space */
- if ( copy_from_user((char*)inp + (int)inp->coda_ioctl.data,
+ if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
data->vi.in, data->vi.in_size) ) {
error = EINVAL;
goto exit;
@@ -567,7 +568,7 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
if ( error ) goto exit;
if (copy_to_user(data->vi.out,
- (char *)outp + (int)outp->coda_ioctl.data,
+ (char *)outp + (long)outp->coda_ioctl.data,
data->vi.out_size)) {
error = EINVAL;
goto exit;
@@ -630,7 +631,7 @@ static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
set_current_state(TASK_UNINTERRUPTIBLE);
/* got a reply */
- if ( vmp->uc_flags & REQ_WRITE )
+ if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
break;
if ( !coda_hard && signal_pending(current) ) {
@@ -660,7 +661,8 @@ static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp)
}
CDEBUG(D_SPECIAL, "begin: %ld.%06ld, elapsed: %ld.%06ld\n",
- begin.tv_sec, begin.tv_usec, end.tv_sec, end.tv_usec);
+ begin.tv_sec, (unsigned long)begin.tv_usec,
+ end.tv_sec, (unsigned long)end.tv_usec);
return ((end.tv_sec * 1000000) + end.tv_usec);
}
@@ -844,7 +846,6 @@ ENTRY;
int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
{
-
/* Handle invalidation requests. */
if ( !sb || !sb->s_root || !sb->s_root->d_inode) {
printk("coda_downcall: opcode %d, no sb!\n", opcode);
@@ -877,7 +878,8 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
case CODA_ZAPDIR : {
struct inode *inode;
ViceFid *fid = &out->coda_zapdir.CodaFid;
- CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid));
+ CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n",
+ coda_f2s(fid));
clstats(CODA_ZAPDIR);
inode = coda_fid_to_inode(fid, sb);
@@ -887,6 +889,7 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
coda_flag_inode_children(inode, C_PURGE);
CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino);
coda_flag_inode(inode, C_VATTR);
+ iput(inode);
} else
CDEBUG(D_DOWNCALL, "zapdir: no inode\n");
@@ -897,11 +900,14 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
struct inode *inode;
struct ViceFid *fid = &out->coda_zapfile.CodaFid;
clstats(CODA_ZAPFILE);
- CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
+ CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n",
+ coda_f2s(fid));
inode = coda_fid_to_inode(fid, sb);
if ( inode ) {
- CDEBUG(D_DOWNCALL, "zapfile: inode = %ld\n", inode->i_ino);
+ CDEBUG(D_DOWNCALL, "zapfile: inode = %ld\n",
+ inode->i_ino);
coda_flag_inode(inode, C_VATTR);
+ iput(inode);
} else
CDEBUG(D_DOWNCALL, "zapfile: no inode\n");
return 0;
@@ -910,18 +916,61 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
case CODA_PURGEFID : {
struct inode *inode;
ViceFid *fid = &out->coda_purgefid.CodaFid;
- CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
+ CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n",
+ coda_f2s(fid));
clstats(CODA_PURGEFID);
inode = coda_fid_to_inode(fid, sb);
if ( inode ) {
- CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n", inode->i_ino);
+ CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n",
+ inode->i_ino);
coda_flag_inode_children(inode, C_PURGE);
coda_purge_dentries(inode);
+ iput(inode);
}else
CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
return 0;
}
+ case CODA_MAKE_CINODE : {
+ struct inode *inode;
+ ViceFid *fid = &out->coda_make_cinode.CodaFid;
+ struct coda_vattr *attr = &out->coda_make_cinode.attr;
+ int fd = out->coda_make_cinode.fd;
+ struct file *file;
+ CDEBUG(D_DOWNCALL, "make_cinode: fid = %s, ino = %ld\n",
+ coda_f2s(fid), attr->va_fileid);
+
+ inode = coda_iget(sb, fid, attr);
+ if ( !inode ) {
+ CDEBUG(D_DOWNCALL, "make_cinode: no inode\n");
+ return -EINVAL;
+ }
+
+ file = fget(fd);
+ if ( !file ) {
+ CDEBUG(D_DOWNCALL, "make_cinode: no file\n");
+ iput(inode);
+ return -EINVAL;
+ }
+
+ inode->u.coda_i.c_ovp = file->f_dentry->d_inode;
+ inode->i_mapping = file->f_dentry->d_inode->i_mapping;
+ file->f_dentry->d_inode = inode;
+ file->f_op = &coda_file_operations;
+
+ /*
+ Unhash the dentry of the container file, as it is
+ still owned by the fs that stores the container
+ file. A more reliable solution would be to create
+ an new dentry owned by Coda, but that would require
+ knowledge of the internals of the dcache.
+ */
+ d_drop(file->f_dentry);
+
+ fput(file);
+ return 0;
+ }
+
case CODA_REPLACE : {
struct inode *inode;
ViceFid *oldfid = &out->coda_replace.OldFid;
@@ -932,6 +981,7 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
if ( inode ) {
CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n", inode->i_ino);
coda_replace_fid(inode, oldfid, newfid);
+ iput(inode);
}else
CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
@@ -941,5 +991,3 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
return 0;
}
-
-
diff --git a/fs/cramfs/inflate/zconf.h b/fs/cramfs/inflate/zconf.h
index adc70c276..0b5ec8838 100644
--- a/fs/cramfs/inflate/zconf.h
+++ b/fs/cramfs/inflate/zconf.h
@@ -83,8 +83,8 @@ typedef uLong FAR uLongf;
typedef void FAR *voidpf;
typedef void *voidp;
-#include <sys/types.h> /* for off_t */
-#include <unistd.h> /* for SEEK_* and off_t */
+#include <linux/types.h> /* for off_t */
+#include <linux/unistd.h> /* for SEEK_* and off_t */
#define z_off_t off_t
#endif /* _ZCONF_H */
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 07c8f15a1..b9ab3c4c4 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -25,7 +25,7 @@
static struct super_operations cramfs_ops;
static struct inode_operations cramfs_file_inode_operations;
static struct inode_operations cramfs_dir_inode_operations;
-static struct inode_operations cramfs_symlink_inode_operations;
+static struct address_space_operations cramfs_aops;
/* These two macros may change in future, to provide better st_ino
semantics. */
@@ -51,13 +51,15 @@ static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inod
result in GNU find, even
without -noleaf option. */
insert_inode_hash(inode);
- if (S_ISREG(inode->i_mode))
+ if (S_ISREG(inode->i_mode)) {
inode->i_op = &cramfs_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
+ inode->i_data.a_ops = &cramfs_aops;
+ } else if (S_ISDIR(inode->i_mode))
inode->i_op = &cramfs_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &cramfs_symlink_inode_operations;
- else {
+ else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_data.a_ops = &cramfs_aops;
+ } else {
inode->i_size = 0;
init_special_inode(inode, inode->i_mode, cramfs_inode->size);
}
@@ -344,53 +346,9 @@ static int cramfs_readpage(struct dentry *dentry, struct page * page)
return 0;
}
-static struct page *get_symlink_page(struct dentry *dentry)
-{
- return read_cache_page(&dentry->d_inode->i_data, 0, (filler_t *)cramfs_readpage, dentry);
-}
-
-static int cramfs_readlink(struct dentry *dentry, char *buffer, int len)
-{
- struct inode *inode = dentry->d_inode;
- int retval;
-
- if (!inode || !S_ISLNK(inode->i_mode))
- return -EBADF;
-
- retval = inode->i_size;
- if (retval) {
- int len;
- struct page *page = get_symlink_page(dentry);
-
- if (IS_ERR(page))
- return PTR_ERR(page);
- wait_on_page(page);
- len = retval;
- retval = -EIO;
- if (Page_Uptodate(page)) {
- retval = -EFAULT;
- if (!copy_to_user(buffer, (void *) page_address(page), len))
- retval = len;
- }
- page_cache_release(page);
- }
- return retval;
-}
-
-static struct dentry *cramfs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow)
-{
- struct page *page = get_symlink_page(dentry);
- struct dentry *result;
-
- if (IS_ERR(page)) {
- dput(base);
- return ERR_PTR(PTR_ERR(page));
- }
-
- result = lookup_dentry((void *) page_address(page), base, follow);
- page_cache_release(page);
- return result;
-}
+static struct address_space_operations cramfs_aops = {
+ readpage: cramfs_readpage
+};
/*
* Our operations:
@@ -398,99 +356,25 @@ static struct dentry *cramfs_follow_link(struct dentry *dentry, struct dentry *b
* A regular file can be read and mmap'ed.
*/
static struct file_operations cramfs_file_operations = {
- NULL, /* lseek - default */
- generic_file_read, /* read */
- NULL, /* write - bad */
- NULL, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl */
- generic_file_mmap, /* mmap */
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
+ read: generic_file_read,
+ mmap: generic_file_mmap,
};
/*
* A directory can only readdir
*/
static struct file_operations cramfs_directory_operations = {
- NULL, /* lseek - default */
- NULL, /* read */
- NULL, /* write - bad */
- cramfs_readdir, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
+ readdir: cramfs_readdir,
};
static struct inode_operations cramfs_file_inode_operations = {
&cramfs_file_operations,
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- cramfs_readpage, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
static struct inode_operations cramfs_dir_inode_operations = {
&cramfs_directory_operations,
NULL, /* create */
cramfs_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
-};
-
-static struct inode_operations cramfs_symlink_inode_operations = {
- NULL, /* symlinks do not have files */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- cramfs_readlink, /* readlink */
- cramfs_follow_link, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
static struct super_operations cramfs_ops = {
diff --git a/fs/devices.c b/fs/devices.c
index 36e15475a..607a96edd 100644
--- a/fs/devices.c
+++ b/fs/devices.c
@@ -157,7 +157,7 @@ int chrdev_open(struct inode * inode, struct file * filp)
* depending on the special file...
*/
static struct file_operations def_chr_fops = {
- open: chrdev_open
+ open: chrdev_open,
};
static struct inode_operations chrdev_inode_operations = {
diff --git a/fs/devpts/root.c b/fs/devpts/root.c
index 92978217f..5af3967e2 100644
--- a/fs/devpts/root.c
+++ b/fs/devpts/root.c
@@ -21,31 +21,13 @@ static struct dentry *devpts_root_lookup(struct inode *,struct dentry *);
static int devpts_revalidate(struct dentry *, int);
static struct file_operations devpts_root_operations = {
- NULL, /* llseek */
- NULL, /* read */
- NULL, /* write */
- devpts_root_readdir, /* readdir */
+ readdir: devpts_root_readdir,
};
struct inode_operations devpts_root_inode_operations = {
&devpts_root_operations, /* file operations */
NULL, /* create */
devpts_root_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
static struct dentry_operations devpts_dentry_operations = {
diff --git a/fs/efs/dir.c b/fs/efs/dir.c
index 4e84b1abb..1283f9fdc 100644
--- a/fs/efs/dir.c
+++ b/fs/efs/dir.c
@@ -9,41 +9,13 @@
static int efs_readdir(struct file *, void *, filldir_t);
static struct file_operations efs_dir_operations = {
- NULL, /* lseek */
- NULL, /* read */
- NULL, /* write */
- efs_readdir, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
+ readdir: efs_readdir,
};
-extern int efs_get_block(struct inode *, long, struct buffer_head *, int);
-
struct inode_operations efs_dir_inode_operations = {
&efs_dir_operations, /* default directory file-ops */
NULL, /* create */
efs_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- efs_get_block, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
diff --git a/fs/efs/file.c b/fs/efs/file.c
index 8a2a8163d..3c6de9b28 100644
--- a/fs/efs/file.c
+++ b/fs/efs/file.c
@@ -62,37 +62,10 @@ int efs_bmap(struct inode *inode, efs_block_t block) {
}
static struct file_operations efs_file_operations = {
- NULL, /* lseek */
- generic_file_read, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- generic_file_mmap, /* mmap */
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
+ read: generic_file_read,
+ mmap: generic_file_mmap,
};
struct inode_operations efs_file_inode_operations = {
&efs_file_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- efs_get_block, /* get_block */
- block_read_full_page, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
diff --git a/fs/efs/inode.c b/fs/efs/inode.c
index 75903be12..0206ae6d5 100644
--- a/fs/efs/inode.c
+++ b/fs/efs/inode.c
@@ -10,6 +10,20 @@
#include <linux/efs_fs.h>
#include <linux/efs_fs_sb.h>
+extern int efs_get_block(struct inode *, long, struct buffer_head *, int);
+static int efs_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,efs_get_block);
+}
+static int _efs_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,efs_get_block);
+}
+struct address_space_operations efs_aops = {
+ readpage: efs_readpage,
+ bmap: _efs_bmap
+};
+
static inline void extent_copy(efs_extent *src, efs_extent *dst) {
/*
* this is slightly evil. it doesn't just copy
@@ -126,9 +140,11 @@ void efs_read_inode(struct inode *inode) {
break;
case S_IFREG:
inode->i_op = &efs_file_inode_operations;
+ inode->i_data.a_ops = &efs_aops;
break;
case S_IFLNK:
- inode->i_op = &efs_symlink_inode_operations;
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_data.a_ops = &efs_symlink_aops;
break;
case S_IFCHR:
case S_IFBLK:
diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c
index 6bfc16be7..66776c7e5 100644
--- a/fs/efs/symlink.c
+++ b/fs/efs/symlink.c
@@ -48,8 +48,6 @@ fail:
return err;
}
-struct inode_operations efs_symlink_inode_operations = {
- readlink: page_readlink,
- follow_link: page_follow_link,
+struct address_space_operations efs_symlink_aops = {
readpage: efs_symlink_readpage
};
diff --git a/fs/exec.c b/fs/exec.c
index 7a7858066..efbf9a8ef 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -265,7 +265,7 @@ int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm)
* This routine is used to map in a page into an address space: needed by
* execve() for the initial stack and environment pages.
*/
-static void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address)
+void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address)
{
pgd_t * pgd;
pmd_t * pmd;
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index c97292620..1d45d3514 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -31,18 +31,10 @@ static ssize_t ext2_dir_read (struct file * filp, char * buf,
static int ext2_readdir(struct file *, void *, filldir_t);
static struct file_operations ext2_dir_operations = {
- NULL, /* lseek - default */
- ext2_dir_read, /* read */
- NULL, /* write - bad */
- ext2_readdir, /* readdir */
- NULL, /* poll - default */
- ext2_ioctl, /* ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- ext2_sync_file, /* fsync */
- NULL, /* fasync */
+ read: ext2_dir_read,
+ readdir: ext2_readdir,
+ ioctl: ext2_ioctl,
+ fsync: ext2_sync_file,
};
/*
@@ -59,14 +51,6 @@ struct inode_operations ext2_dir_inode_operations = {
ext2_rmdir, /* rmdir */
ext2_mknod, /* mknod */
ext2_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
int ext2_check_dir_entry (const char * function, struct inode * dir,
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index df010f223..5c4639175 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -21,13 +21,6 @@
#include <linux/fs.h>
#include <linux/sched.h>
-
-
-#define NBUF 32
-
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-
static loff_t ext2_file_lseek(struct file *, loff_t, int);
static int ext2_open_file (struct inode *, struct file *);
@@ -73,40 +66,6 @@ static loff_t ext2_file_lseek(
return offset;
}
-static inline void remove_suid(struct inode *inode)
-{
- unsigned int mode;
-
- /* set S_IGID if S_IXGRP is set, and always set S_ISUID */
- mode = (inode->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID;
-
- /* was any of the uid bits set? */
- mode &= inode->i_mode;
- if (mode && !capable(CAP_FSETID)) {
- inode->i_mode &= ~mode;
- mark_inode_dirty(inode);
- }
-}
-
-/*
- * Write to a file (through the page cache).
- */
-static ssize_t
-ext2_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
-{
- ssize_t retval;
-
- retval = generic_file_write(file, buf, count,
- ppos, block_write_partial_page);
- if (retval > 0) {
- struct inode *inode = file->f_dentry->d_inode;
- remove_suid(inode);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- mark_inode_dirty(inode);
- }
- return retval;
-}
-
/*
* Called when an inode is released. Note that this is different
* from ext2_file_open: open gets called at every open, but release
@@ -137,37 +96,17 @@ static int ext2_open_file (struct inode * inode, struct file * filp)
* the ext2 filesystem.
*/
static struct file_operations ext2_file_operations = {
- ext2_file_lseek, /* lseek */
- generic_file_read, /* read */
- ext2_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- ext2_ioctl, /* ioctl */
- generic_file_mmap, /* mmap */
- ext2_open_file,
- NULL, /* flush */
- ext2_release_file, /* release */
- ext2_sync_file, /* fsync */
- NULL, /* fasync */
+ llseek: ext2_file_lseek,
+ read: generic_file_read,
+ write: generic_file_write,
+ ioctl: ext2_ioctl,
+ mmap: generic_file_mmap,
+ open: ext2_open_file,
+ release: ext2_release_file,
+ fsync: ext2_sync_file,
};
struct inode_operations ext2_file_inode_operations = {
- &ext2_file_operations,/* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- ext2_get_block, /* get_block */
- block_read_full_page, /* readpage */
- block_write_full_page, /* writepage */
- ext2_truncate, /* truncate */
- NULL, /* permission */
- NULL, /* revalidate */
+ &ext2_file_operations,
+ truncate: ext2_truncate,
};
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index c29fef5ea..52ffd6138 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -24,8 +24,7 @@
#include <linux/fs.h>
#include <linux/locks.h>
-
-
+#include <linux/smp_lock.h>
#define blocksize (EXT2_BLOCK_SIZE(inode->i_sb))
@@ -130,6 +129,7 @@ int ext2_sync_file(struct file * file, struct dentry *dentry)
int wait, err = 0;
struct inode *inode = dentry->d_inode;
+ lock_kernel();
if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
/*
* Don't sync fast links!
@@ -152,5 +152,6 @@ int ext2_sync_file(struct file * file, struct dentry *dentry)
}
skip:
err |= ext2_sync_inode (inode);
+ unlock_kernel();
return err ? -EIO : 0;
}
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index e92e4080a..ab7ac0a96 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -408,7 +408,7 @@ out:
return result;
}
-int ext2_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create)
+static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create)
{
int ret, err, new;
struct buffer_head *bh;
@@ -610,6 +610,30 @@ struct buffer_head * ext2_bread (struct inode * inode, int block,
return NULL;
}
+static int ext2_writepage(struct dentry *dentry, struct page *page)
+{
+ return block_write_full_page(page,ext2_get_block);
+}
+static int ext2_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,ext2_get_block);
+}
+static int ext2_prepare_write(struct page *page, unsigned from, unsigned to)
+{
+ return block_prepare_write(page,from,to,ext2_get_block);
+}
+static int ext2_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,ext2_get_block);
+}
+struct address_space_operations ext2_aops = {
+ readpage: ext2_readpage,
+ writepage: ext2_writepage,
+ prepare_write: ext2_prepare_write,
+ commit_write: generic_commit_write,
+ bmap: ext2_bmap
+};
+
void ext2_read_inode (struct inode * inode)
{
struct buffer_head * bh;
@@ -719,15 +743,19 @@ void ext2_read_inode (struct inode * inode)
if (inode->i_ino == EXT2_ACL_IDX_INO ||
inode->i_ino == EXT2_ACL_DATA_INO)
/* Nothing to do */ ;
- else if (S_ISREG(inode->i_mode))
+ else if (S_ISREG(inode->i_mode)) {
inode->i_op = &ext2_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
+ inode->i_mapping->a_ops = &ext2_aops;
+ } else if (S_ISDIR(inode->i_mode))
inode->i_op = &ext2_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = inode->i_blocks
- ?&ext2_symlink_inode_operations
- :&ext2_fast_symlink_inode_operations;
- else
+ else if (S_ISLNK(inode->i_mode)) {
+ if (!inode->i_blocks)
+ inode->i_op = &ext2_fast_symlink_inode_operations;
+ else {
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_mapping->a_ops = &ext2_aops;
+ }
+ } else
init_special_inode(inode, inode->i_mode,
le32_to_cpu(raw_inode->i_block[0]));
brelse (bh);
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 08136962a..c2e5630ca 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -384,6 +384,7 @@ int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
return err;
inode->i_op = &ext2_file_inode_operations;
+ inode->i_mapping->a_ops = &ext2_aops;
inode->i_mode = mode;
mark_inode_dirty(inode);
bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
@@ -696,7 +697,8 @@ int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symnam
inode->i_mode = S_IFLNK | S_IRWXUGO;
if (l > sizeof (inode->u.ext2_i.i_data)) {
- inode->i_op = &ext2_symlink_inode_operations;
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_mapping->a_ops = &ext2_aops;
err = block_symlink(inode, symname, l);
if (err)
goto out_no_entry;
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index 18fbbb368..d56ef4c62 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -1,6 +1,8 @@
/*
* linux/fs/ext2/symlink.c
*
+ * Only fast symlinks left here - the rest is done by generic code. AV, 1999
+ *
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
@@ -16,7 +18,6 @@
*/
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
static int ext2_readlink(struct dentry *dentry, char *buffer, int buflen)
{
@@ -34,10 +35,3 @@ struct inode_operations ext2_fast_symlink_inode_operations = {
readlink: ext2_readlink,
follow_link: ext2_follow_link,
};
-
-struct inode_operations ext2_symlink_inode_operations = {
- readlink: page_readlink,
- follow_link: page_follow_link,
- get_block: ext2_get_block,
- readpage: block_read_full_page,
-};
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index 45f4a800c..175182959 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -283,7 +283,7 @@ int default_fat_bmap(struct inode *inode,int sector)
return 0;
return sector+sb->dir_start;
}
- if (sector >= (MSDOS_I(inode)->i_realsize>>9))
+ if (sector >= MSDOS_I(inode)->mmu_private>>9)
return 0;
cluster = sector/sb->cluster_size;
offset = sector % sb->cluster_size;
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 83565fcbe..804876270 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -41,17 +41,10 @@ static ssize_t fat_dir_read(struct file * filp, char * buf,
}
struct file_operations fat_dir_operations = {
- NULL, /* lseek - default */
- fat_dir_read, /* read */
- NULL, /* write - bad */
- fat_readdir, /* readdir */
- NULL, /* select v2.0.x/poll v2.1.x - default */
- fat_dir_ioctl, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- file_fsync /* fsync */
+ read: fat_dir_read,
+ readdir: fat_readdir,
+ ioctl: fat_dir_ioctl,
+ fsync: file_fsync,
};
/*
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 06da340fb..0c535b8da 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -31,17 +31,10 @@
#define Printk(x) printk x
static struct file_operations fat_file_operations = {
- NULL, /* lseek - default */
- fat_file_read, /* read */
- fat_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* select v2.0.x/poll v2.1.x - default */
- NULL, /* ioctl - default */
- generic_file_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- NULL, /* release */
- file_fsync /* fsync */
+ read: fat_file_read,
+ write: fat_file_write,
+ mmap: generic_file_mmap,
+ fsync: file_fsync,
};
struct inode_operations fat_file_inode_operations = {
@@ -57,12 +50,7 @@ struct inode_operations fat_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- fat_get_block, /* get_block */
- block_read_full_page, /* readpage */
- NULL, /* writepage */
fat_truncate, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
ssize_t fat_file_read(
@@ -88,7 +76,7 @@ int fat_get_block(struct inode *inode, long iblock, struct buffer_head *bh_resul
}
if (!create)
return 0;
- if (iblock<<9 != MSDOS_I(inode)->i_realsize) {
+ if (iblock<<9 != MSDOS_I(inode)->mmu_private) {
BUG();
return -EIO;
}
@@ -96,7 +84,7 @@ int fat_get_block(struct inode *inode, long iblock, struct buffer_head *bh_resul
if (fat_add_cluster(inode))
return -ENOSPC;
}
- MSDOS_I(inode)->i_realsize+=SECTOR_SIZE;
+ MSDOS_I(inode)->mmu_private += 512;
phys=fat_bmap(inode, iblock);
if (!phys)
BUG();
@@ -107,30 +95,6 @@ int fat_get_block(struct inode *inode, long iblock, struct buffer_head *bh_resul
return 0;
}
-static int fat_write_partial_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
-{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
- struct page *new_page;
- unsigned long pgpos;
- long status;
-
- while((pgpos=MSDOS_I(inode)->i_realsize>>PAGE_CACHE_SHIFT)<page->index){
- status = -ENOMEM;
- new_page = grab_cache_page(&inode->i_data, pgpos);
- if (!new_page)
- goto out;
- status = block_write_cont_page(file, new_page, PAGE_SIZE, 0, NULL);
- UnlockPage(new_page);
- page_cache_release(new_page);
- if (status < 0)
- goto out;
- }
- status = block_write_cont_page(file, page, offset, bytes, buf);
-out:
- return status;
-}
-
ssize_t fat_file_write(
struct file *filp,
const char *buf,
@@ -152,8 +116,7 @@ ssize_t default_fat_file_write(
struct inode *inode = filp->f_dentry->d_inode;
int retval;
- retval = generic_file_write(filp, buf, count, ppos,
- fat_write_partial_page);
+ retval = generic_file_write(filp, buf, count, ppos);
if (retval > 0) {
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
@@ -173,7 +136,7 @@ void fat_truncate(struct inode *inode)
if (IS_IMMUTABLE(inode))
return /* -EPERM */;
cluster = SECTOR_SIZE*sbi->cluster_size;
- MSDOS_I(inode)->i_realsize = ((inode->i_size-1) | (SECTOR_SIZE-1)) + 1;
+ MSDOS_I(inode)->mmu_private = inode->i_size;
fat_free(inode,(inode->i_size+(cluster-1))>>sbi->cluster_bits);
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 3919f6517..90b288832 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -397,7 +397,7 @@ static void fat_read_root(struct inode *inode)
((inode->i_size+inode->i_blksize-1)>>sbi->cluster_bits) *
sbi->cluster_size;
MSDOS_I(inode)->i_logstart = 0;
- MSDOS_I(inode)->i_realsize = inode->i_size;
+ MSDOS_I(inode)->mmu_private = inode->i_size;
MSDOS_I(inode)->i_attrs = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
@@ -746,6 +746,31 @@ static int is_exec(char *extension)
return 0;
}
+static int fat_writepage(struct dentry *dentry, struct page *page)
+{
+ return block_write_full_page(page,fat_get_block);
+}
+static int fat_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,fat_get_block);
+}
+static int fat_prepare_write(struct page *page, unsigned from, unsigned to)
+{
+ return cont_prepare_write(page,from,to,fat_get_block,
+ &MSDOS_I((struct inode*)page->mapping->host)->mmu_private);
+}
+static int _fat_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,fat_get_block);
+}
+static struct address_space_operations fat_aops = {
+ readpage: fat_readpage,
+ writepage: fat_writepage,
+ prepare_write: fat_prepare_write,
+ commit_write: generic_commit_write,
+ bmap: _fat_bmap
+};
+
/* doesn't deal with root inode */
static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
{
@@ -788,7 +813,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
break;
}
}
- MSDOS_I(inode)->i_realsize = inode->i_size;
+ MSDOS_I(inode)->mmu_private = inode->i_size;
} else { /* not a directory */
inode->i_mode = MSDOS_MKMODE(de->attr,
((IS_NOEXEC(inode) ||
@@ -796,7 +821,6 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
!is_exec(de->ext)))
? S_IRUGO|S_IWUGO : S_IRWXUGO)
& ~sbi->options.fs_umask) | S_IFREG;
- inode->i_op = &fat_file_inode_operations;
MSDOS_I(inode)->i_start = CF_LE_W(de->start);
if (sbi->fat_bits == 32) {
MSDOS_I(inode)->i_start |=
@@ -805,7 +829,9 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
inode->i_nlink = 1;
inode->i_size = CF_LE_L(de->size);
- MSDOS_I(inode)->i_realsize = ((inode->i_size-1)|(SECTOR_SIZE-1))+1;
+ inode->i_op = &fat_file_inode_operations;
+ inode->i_mapping->a_ops = &fat_aops;
+ MSDOS_I(inode)->mmu_private = inode->i_size;
}
if(de->attr & ATTR_SYS)
if (sbi->options.sys_immutable)
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 196e7aa1b..bca75467b 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -311,7 +311,7 @@ if (last) printk("next set to %d\n",fat_access(sb,last,-1));
~(SECTOR_SIZE-1);
}
inode->i_size += SECTOR_SIZE*cluster_size;
- MSDOS_I(inode)->i_realsize += SECTOR_SIZE*cluster_size;
+ MSDOS_I(inode)->mmu_private += SECTOR_SIZE*cluster_size;
mark_inode_dirty(inode);
return res;
}
diff --git a/fs/fifo.c b/fs/fifo.c
index 88d8bd33b..fd48328e9 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -153,7 +153,7 @@ err_nolock_nocleanup:
* depending on the access mode of the file...
*/
static struct file_operations def_fifo_fops = {
- open: fifo_open, /* will set read or write pipe_fops */
+ open: fifo_open, /* will set read or write pipe_fops */
};
struct inode_operations fifo_inode_operations = {
diff --git a/fs/hfs/dir_cap.c b/fs/hfs/dir_cap.c
index cdf01737a..e0dab7583 100644
--- a/fs/hfs/dir_cap.c
+++ b/fs/hfs/dir_cap.c
@@ -58,18 +58,9 @@ const struct hfs_name hfs_cap_reserved2[] = {
#define DOT_ROOTINFO (&hfs_cap_reserved2[0])
static struct file_operations hfs_cap_dir_operations = {
- NULL, /* lseek - default */
- hfs_dir_read, /* read - invalid */
- NULL, /* write - bad */
- cap_readdir, /* readdir */
- NULL, /* select - default */
- NULL, /* ioctl - default */
- NULL, /* mmap - none */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- file_fsync, /* fsync - default */
- NULL, /* fasync - default */
+ read: hfs_dir_read,
+ readdir: cap_readdir,
+ fsync: file_fsync,
};
struct inode_operations hfs_cap_ndir_inode_operations = {
@@ -83,56 +74,18 @@ struct inode_operations hfs_cap_ndir_inode_operations = {
hfs_rmdir, /* rmdir */
NULL, /* mknod */
hfs_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
struct inode_operations hfs_cap_fdir_inode_operations = {
&hfs_cap_dir_operations,/* default directory file-ops */
NULL, /* create */
cap_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
struct inode_operations hfs_cap_rdir_inode_operations = {
&hfs_cap_dir_operations,/* default directory file-ops */
hfs_create, /* create */
cap_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
/*================ File-local functions ================*/
diff --git a/fs/hfs/dir_dbl.c b/fs/hfs/dir_dbl.c
index 1e13465d1..f3469b402 100644
--- a/fs/hfs/dir_dbl.c
+++ b/fs/hfs/dir_dbl.c
@@ -57,18 +57,9 @@ const struct hfs_name hfs_dbl_reserved2[] = {
#define PCNT_ROOTINFO (&hfs_dbl_reserved2[1])
static struct file_operations hfs_dbl_dir_operations = {
- NULL, /* lseek - default */
- hfs_dir_read, /* read - invalid */
- NULL, /* write - bad */
- dbl_readdir, /* readdir */
- NULL, /* select - default */
- NULL, /* ioctl - default */
- NULL, /* mmap - none */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- file_fsync, /* fsync - default */
- NULL, /* fasync - default */
+ read: hfs_dir_read,
+ readdir: dbl_readdir,
+ fsync: file_fsync,
};
struct inode_operations hfs_dbl_dir_inode_operations = {
@@ -82,14 +73,6 @@ struct inode_operations hfs_dbl_dir_inode_operations = {
dbl_rmdir, /* rmdir */
NULL, /* mknod */
dbl_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
diff --git a/fs/hfs/dir_nat.c b/fs/hfs/dir_nat.c
index ab274d18f..05a646384 100644
--- a/fs/hfs/dir_nat.c
+++ b/fs/hfs/dir_nat.c
@@ -63,19 +63,9 @@ const struct hfs_name hfs_nat_reserved2[] = {
#define ROOTINFO (&hfs_nat_reserved2[0])
static struct file_operations hfs_nat_dir_operations = {
- NULL, /* lseek - default */
- hfs_dir_read, /* read - invalid */
- NULL, /* write - bad */
- nat_readdir, /* readdir */
- NULL, /* select - default */
- NULL, /* ioctl - default */
- NULL, /* mmap - none */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- file_fsync, /* fsync - default */
- NULL, /* fasync - default */
- NULL /* lock - none */
+ read: hfs_dir_read,
+ readdir: nat_readdir,
+ fsync: file_fsync,
};
struct inode_operations hfs_nat_ndir_inode_operations = {
@@ -89,14 +79,6 @@ struct inode_operations hfs_nat_ndir_inode_operations = {
nat_rmdir, /* rmdir */
NULL, /* mknod */
hfs_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
struct inode_operations hfs_nat_hdir_inode_operations = {
@@ -110,14 +92,6 @@ struct inode_operations hfs_nat_hdir_inode_operations = {
NULL, /* rmdir */
NULL, /* mknod */
nat_hdr_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
/*================ File-local functions ================*/
diff --git a/fs/hfs/file.c b/fs/hfs/file.c
index d5edeac45..bb0868fca 100644
--- a/fs/hfs/file.c
+++ b/fs/hfs/file.c
@@ -28,24 +28,14 @@ static hfs_rwret_t hfs_file_read(struct file *, char *, hfs_rwarg_t,
static hfs_rwret_t hfs_file_write(struct file *, const char *, hfs_rwarg_t,
loff_t *);
static void hfs_file_truncate(struct inode *);
-static int hfs_get_block(struct inode *, long, struct buffer_head *, int);
/*================ Global variables ================*/
static struct file_operations hfs_file_operations = {
- NULL, /* lseek - default */
- hfs_file_read, /* read */
- hfs_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* select - default */
- NULL, /* ioctl - default */
- generic_file_mmap, /* mmap */
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- file_fsync, /* fsync - default */
- NULL, /* fasync - default */
- NULL /* lock - none */
+ read: hfs_file_read,
+ write: hfs_file_write,
+ mmap: generic_file_mmap,
+ fsync: file_fsync,
};
struct inode_operations hfs_file_inode_operations = {
@@ -61,12 +51,7 @@ struct inode_operations hfs_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- hfs_get_block, /* get_block */
- block_read_full_page, /* readpage */
- NULL, /* writepage */
hfs_file_truncate, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
/*================ Variable-like macros ================*/
diff --git a/fs/hfs/file_cap.c b/fs/hfs/file_cap.c
index 4e723af63..77625077f 100644
--- a/fs/hfs/file_cap.c
+++ b/fs/hfs/file_cap.c
@@ -47,19 +47,9 @@ static void cap_info_truncate(struct inode *);
/*================ Global variables ================*/
static struct file_operations hfs_cap_info_operations = {
- NULL, /* lseek - default */
- cap_info_read, /* read */
- cap_info_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* select - default */
- NULL, /* ioctl - default */
- NULL, /* mmap - not yet */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- file_fsync, /* fsync - default */
- NULL, /* fasync - default */
- NULL /* lock - none */
+ read: cap_info_read,
+ write: cap_info_write,
+ fsync: file_fsync,
};
struct inode_operations hfs_cap_info_inode_operations = {
@@ -75,12 +65,7 @@ struct inode_operations hfs_cap_info_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* get_block - none */
- NULL, /* readpage */
- NULL, /* writepage */
cap_info_truncate, /* truncate */
- NULL, /* permission */
- NULL /* revalidata */
};
/*================ File-local functions ================*/
diff --git a/fs/hfs/file_hdr.c b/fs/hfs/file_hdr.c
index efbe84f75..b0cf0291e 100644
--- a/fs/hfs/file_hdr.c
+++ b/fs/hfs/file_hdr.c
@@ -48,19 +48,9 @@ static void hdr_truncate(struct inode *);
/*================ Global variables ================*/
static struct file_operations hfs_hdr_operations = {
- NULL, /* lseek - default */
- hdr_read, /* read */
- hdr_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* select - default */
- NULL, /* ioctl - default */
- NULL, /* mmap - XXX: not yet */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- file_fsync, /* fsync - default */
- NULL, /* fasync - default */
- NULL /* lock - none */
+ read: hdr_read,
+ write: hdr_write,
+ fsync: file_fsync,
};
struct inode_operations hfs_hdr_inode_operations = {
@@ -76,13 +66,7 @@ struct inode_operations hfs_hdr_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* get_block - XXX: not available since
- header part has no disk block */
- NULL, /* readpage */
- NULL, /* writepage */
hdr_truncate, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
const struct hfs_hdr_layout hfs_dbl_fil_hdr_layout = {
diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h
index 07e61f0de..3819a685f 100644
--- a/fs/hfs/hfs.h
+++ b/fs/hfs/hfs.h
@@ -494,6 +494,9 @@ extern int hfs_extent_map(struct hfs_fork *, int, int);
extern void hfs_extent_adj(struct hfs_fork *);
extern void hfs_extent_free(struct hfs_fork *);
+/* file.c */
+extern int hfs_get_block(struct inode *, long, struct buffer_head *, int);
+
/* mdb.c */
extern struct hfs_mdb *hfs_mdb_get(hfs_sysmdb, int, hfs_s32);
extern void hfs_mdb_commit(struct hfs_mdb *, int);
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index af09655a0..60014426b 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -184,6 +184,31 @@ int hfs_notify_change(struct dentry *dentry, struct iattr * attr)
return 0;
}
+static int hfs_writepage(struct dentry *dentry, struct page *page)
+{
+ return block_write_full_page(page,hfs_get_block);
+}
+static int hfs_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,hfs_get_block);
+}
+static int hfs_prepare_write(struct page *page, unsigned from, unsigned to)
+{
+ return cont_prepare_write(page,from,to,hfs_get_block,
+ &((struct inode*)page->mapping->host)->u.hfs_i.mmu_private);
+}
+static int hfs_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,hfs_get_block);
+}
+struct address_space_operations hfs_aops = {
+ readpage: hfs_readpage,
+ writepage: hfs_writepage,
+ prepare_write: hfs_prepare_write,
+ commit_write: generic_commit_write,
+ bmap: hfs_bmap
+};
+
/*
* __hfs_iget()
*
@@ -308,6 +333,8 @@ void hfs_cap_ifill(struct inode * inode, ino_t type, const int version)
init_file_inode(inode, (type == HFS_CAP_DATA) ?
HFS_FK_DATA : HFS_FK_RSRC);
inode->i_op = &hfs_file_inode_operations;
+ inode->i_mapping->a_ops = &hfs_aops;
+ inode->u.hfs_i.mmu_private = inode->i_size;
} else { /* Directory */
struct hfs_dir *hdir = &entry->u.dir;
@@ -361,6 +388,8 @@ void hfs_dbl_ifill(struct inode * inode, ino_t type, const int version)
} else if (entry->type == HFS_CDR_FIL) {
init_file_inode(inode, HFS_FK_DATA);
inode->i_op = &hfs_file_inode_operations;
+ inode->i_mapping->a_ops = &hfs_aops;
+ inode->u.hfs_i.mmu_private = inode->i_size;
} else { /* Directory */
struct hfs_dir *hdir = &entry->u.dir;
@@ -402,6 +431,8 @@ void hfs_nat_ifill(struct inode * inode, ino_t type, const int version)
} else if (entry->type == HFS_CDR_FIL) {
init_file_inode(inode, HFS_FK_DATA);
inode->i_op = &hfs_file_inode_operations;
+ inode->i_mapping->a_ops = &hfs_aops;
+ inode->u.hfs_i.mmu_private = inode->i_size;
} else { /* Directory */
struct hfs_dir *hdir = &entry->u.dir;
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
index 36e665c32..280c47244 100644
--- a/fs/hpfs/dir.c
+++ b/fs/hpfs/dir.c
@@ -8,7 +8,7 @@
#include "hpfs_fn.h"
-int hpfs_dir_read(struct file *filp, char *name, size_t len, loff_t *loff)
+ssize_t hpfs_dir_read(struct file *filp, char *name, size_t len, loff_t *loff)
{
return -EISDIR;
}
@@ -242,6 +242,8 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry)
if (!de->directory) {
if (result->i_size == -1) {
result->i_size = de->file_size;
+ result->i_data.a_ops = &hpfs_aops;
+ result->u.hpfs_i.mmu_private = result->i_size;
/*
* i_blocks should count the fnode and any anodes.
* We count 1 for the fnode and don't bother about
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index 8abaf2fd3..710b9120b 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -54,6 +54,7 @@ void hpfs_truncate(struct inode *i)
if (IS_IMMUTABLE(i)) return /*-EPERM*/;
i->i_hpfs_n_secs = 0;
i->i_blocks = 1 + ((i->i_size + 511) >> 9);
+ i->u.hpfs_i.mmu_private = i->i_size;
hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9));
hpfs_write_inode(i);
}
@@ -61,63 +62,60 @@ void hpfs_truncate(struct inode *i)
int hpfs_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create)
{
secno s;
- if (iblock < inode->i_blocks - 1) {
- s = hpfs_bmap(inode, iblock);
+ s = hpfs_bmap(inode, iblock);
+ if (s) {
bh_result->b_dev = inode->i_dev;
bh_result->b_blocknr = s;
bh_result->b_state |= (1UL << BH_Mapped);
return 0;
}
if (!create) return 0;
- if (iblock > inode->i_blocks - 1) {
- //hpfs_error(inode->i_sb, "hpfs_get_block beyond file end (requested %08x, inode size %08x", (int)iblock, (int)inode->i_blocks - 1);
- printk("HPFS: could not write beyond file end. This is known bug.\n");
- return -EFSERROR;
+ if (iblock<<9 != inode->u.hpfs_i.mmu_private) {
+ BUG();
+ return -EIO;
}
if ((s = hpfs_add_sector_to_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1)) == -1) {
hpfs_truncate_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1);
return -ENOSPC;
}
inode->i_blocks++;
+ inode->u.hpfs_i.mmu_private += 512;
bh_result->b_dev = inode->i_dev;
bh_result->b_blocknr = s;
bh_result->b_state |= (1UL << BH_Mapped) | (1UL << BH_New);
return 0;
}
-static int hpfs_write_partial_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+static int hpfs_writepage(struct dentry *dentry, struct page *page)
{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
- struct page *new_page;
- unsigned long pgpos;
- long status;
-
- pgpos = ((inode->i_blocks - 1) * 512) >> PAGE_CACHE_SHIFT;
- while (pgpos < page->index) {
- status = -ENOMEM;
- new_page = grab_cache_page(&inode->i_data, pgpos);
- if (!new_page)
- goto out;
- status = block_write_cont_page(file, new_page, PAGE_SIZE, 0, NULL);
- UnlockPage(new_page);
- page_cache_release(new_page);
- if (status < 0)
- goto out;
- pgpos = ((inode->i_blocks - 1) * 512) >> PAGE_CACHE_SHIFT;
- }
- status = block_write_cont_page(file, page, offset, bytes, buf);
-out:
- return status;
+ return block_write_full_page(page,hpfs_get_block);
}
-
+static int hpfs_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,hpfs_get_block);
+}
+static int hpfs_prepare_write(struct page *page, unsigned from, unsigned to)
+{
+ return cont_prepare_write(page,from,to,hpfs_get_block,
+ &((struct inode*)page->mapping->host)->u.hpfs_i.mmu_private);
+}
+static int _hpfs_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,hpfs_get_block);
+}
+struct address_space_operations hpfs_aops = {
+ readpage: hpfs_readpage,
+ writepage: hpfs_writepage,
+ prepare_write: hpfs_prepare_write,
+ commit_write: generic_commit_write,
+ bmap: _hpfs_bmap
+};
ssize_t hpfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
ssize_t retval;
- retval = generic_file_write(file, buf, count,
- ppos, hpfs_write_partial_page);
+ retval = generic_file_write(file, buf, count, ppos);
if (retval > 0) {
struct inode *inode = file->f_dentry->d_inode;
inode->i_mtime = CURRENT_TIME;
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
index d1e70e579..f0324cffa 100644
--- a/fs/hpfs/hpfs_fn.h
+++ b/fs/hpfs/hpfs_fn.h
@@ -224,7 +224,7 @@ void hpfs_set_dentry_operations(struct dentry *);
/* dir.c */
-int hpfs_dir_read(struct file *, char *, size_t, loff_t *);
+ssize_t hpfs_dir_read(struct file *, char *, size_t, loff_t *);
int hpfs_dir_release(struct inode *, struct file *);
loff_t hpfs_dir_lseek(struct file *, loff_t, int);
int hpfs_readdir(struct file *, void *, filldir_t);
@@ -314,3 +314,5 @@ void hpfs_put_super(struct super_block *);
unsigned hpfs_count_one_bitmap(struct super_block *, secno);
int hpfs_statfs(struct super_block *, struct statfs *, int);
struct super_block *hpfs_read_super(struct super_block *, void *, int);
+
+extern struct address_space_operations hpfs_aops;
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
index 0b6ab8053..2fa2d0dd4 100644
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -10,19 +10,12 @@
static const struct file_operations hpfs_file_ops =
{
- NULL, /* lseek - default */
- generic_file_read, /* read */
- hpfs_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- generic_file_mmap, /* mmap */
- hpfs_open, /* open */
- NULL, /* flush */
- hpfs_file_release, /* release */
- hpfs_file_fsync, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
+ read: generic_file_read,
+ write: hpfs_file_write,
+ mmap: generic_file_mmap,
+ open: hpfs_open,
+ release: hpfs_file_release,
+ fsync: hpfs_file_fsync,
};
static const struct inode_operations hpfs_file_iops =
@@ -39,29 +32,17 @@ static const struct inode_operations hpfs_file_iops =
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- &hpfs_get_block, /* get_block */
- block_read_full_page, /* readpage */
- block_write_full_page, /* writepage */
hpfs_truncate, /* truncate */
- NULL, /* permission */
- NULL, /* revalidate */
};
static const struct file_operations hpfs_dir_ops =
{
- hpfs_dir_lseek, /* lseek */
- hpfs_dir_read, /* read */
- NULL, /* write - bad */
- hpfs_readdir, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- hpfs_open, /* open */
- NULL, /* flush */
- hpfs_dir_release, /* no special release code */
- hpfs_file_fsync, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
+ llseek: hpfs_dir_lseek,
+ read: hpfs_dir_read,
+ readdir: hpfs_readdir,
+ open: hpfs_open,
+ release: hpfs_dir_release,
+ fsync: hpfs_file_fsync,
};
static const struct inode_operations hpfs_dir_iops =
@@ -76,20 +57,9 @@ static const struct inode_operations hpfs_dir_iops =
hpfs_rmdir, /* rmdir */
hpfs_mknod, /* mknod */
hpfs_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
-const struct inode_operations hpfs_symlink_iops =
-{
- readlink: page_readlink,
- follow_link: page_follow_link,
+struct address_space_operations hpfs_symlink_aops = {
readpage: hpfs_symlink_readpage
};
@@ -164,7 +134,8 @@ void hpfs_read_inode(struct inode *i)
if ((ea = hpfs_get_ea(i->i_sb, fnode, "SYMLINK", &ea_size))) {
kfree(ea);
i->i_mode = S_IFLNK | 0777;
- i->i_op = (struct inode_operations *) &hpfs_symlink_iops;
+ i->i_op = &page_symlink_inode_operations;
+ i->i_data.a_ops = &hpfs_symlink_aops;
i->i_nlink = 1;
i->i_size = ea_size;
i->i_blocks = 1;
@@ -219,6 +190,8 @@ void hpfs_read_inode(struct inode *i)
i->i_nlink = 1;
i->i_size = fnode->file_size;
i->i_blocks = ((i->i_size + 511) >> 9) + 1;
+ i->i_data.a_ops = &hpfs_aops;
+ i->u.hpfs_i.mmu_private = i->i_size;
}
brelse(bh);
}
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index 85ce143db..3ca25fedf 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -138,7 +138,11 @@ int hpfs_create(struct inode *dir, struct dentry *dentry, int mode)
result->i_hpfs_ea_size = 0;
if (dee.read_only) result->i_mode &= ~0222;
if (result->i_blocks == -1) result->i_blocks = 1;
- if (result->i_size == -1) result->i_size = 0;
+ if (result->i_size == -1) {
+ result->i_size = 0;
+ result->i_data.a_ops = &hpfs_aops;
+ result->u.hpfs_i.mmu_private = 0;
+ }
if (result->i_uid != current->fsuid ||
result->i_gid != current->fsgid ||
result->i_mode != (mode | S_IFREG)) {
@@ -221,7 +225,7 @@ int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
return -ENOSPC;
}
-extern const struct inode_operations hpfs_symlink_iops;
+extern struct address_space_operations hpfs_symlink_aops;
int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
{
@@ -268,7 +272,8 @@ int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
result->i_gid = current->fsgid;
result->i_blocks = 1;
result->i_size = strlen(symlink);
- result->i_op = (struct inode_operations *) &hpfs_symlink_iops;
+ result->i_op = &page_symlink_inode_operations;
+ result->i_data.a_ops = &hpfs_symlink_aops;
if ((fnode = hpfs_map_fnode(dir->i_sb, fno, &bh))) {
hpfs_set_ea(result, fnode, "SYMLINK", (char *)symlink, strlen(symlink));
mark_buffer_dirty(bh, 1);
diff --git a/fs/inode.c b/fs/inode.c
index 4145a2d91..ccc1a62f3 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -474,6 +474,8 @@ static void clean_inode(struct inode *inode)
memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
inode->i_pipe = NULL;
inode->i_bdev = NULL;
+ inode->i_mapping = &inode->i_data;
+ inode->i_mapping->host = (void*)inode;
}
/*
@@ -719,15 +721,10 @@ kdevname(inode->i_dev), inode->i_ino, atomic_read(&inode->i_sem.count));
int bmap(struct inode * inode, int block)
{
- struct buffer_head tmp;
-
- if (inode->i_op && inode->i_op->get_block) {
- tmp.b_state = 0;
- tmp.b_blocknr = 0;
- inode->i_op->get_block(inode, block, &tmp, 0);
- return tmp.b_blocknr;
- }
- return 0;
+ int res = 0;
+ if (inode->i_mapping->a_ops->bmap)
+ res = inode->i_mapping->a_ops->bmap(inode->i_mapping, block);
+ return res;
}
/*
diff --git a/fs/ioctl.c b/fs/ioctl.c
index e7e226056..a02bbec67 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -19,21 +19,18 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
switch (cmd) {
case FIBMAP:
{
- struct buffer_head tmp;
-
- if (inode->i_op == NULL)
- return -EBADF;
- if (inode->i_op->get_block == NULL)
+ struct address_space *mapping = inode->i_mapping;
+ int res;
+ /* do we support this mess? */
+ if (!mapping->a_ops->bmap)
return -EINVAL;
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
if ((error = get_user(block, (int *) arg)) != 0)
return error;
- tmp.b_state = 0;
- tmp.b_blocknr = 0;
- inode->i_op->get_block(inode, block, &tmp, 0);
- return put_user(tmp.b_blocknr, (int *) arg);
+ res = mapping->a_ops->bmap(mapping, block);
+ return put_user(res, (int *) arg);
}
case FIGETBSZ:
if (inode->i_sb == NULL)
diff --git a/fs/isofs/Makefile b/fs/isofs/Makefile
index 11c340284..2b2af2ade 100644
--- a/fs/isofs/Makefile
+++ b/fs/isofs/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile.
O_TARGET := isofs.o
-O_OBJS := namei.o inode.o file.o dir.o util.o rock.o symlink.o
+O_OBJS := namei.o inode.o file.o dir.o util.o rock.o
ifdef CONFIG_JOLIET
O_OBJS += joliet.o
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index fb60d3a55..35f37a1bf 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -28,16 +28,7 @@ static int isofs_readdir(struct file *, void *, filldir_t);
static struct file_operations isofs_dir_operations =
{
- NULL, /* lseek - default */
- NULL, /* read */
- NULL, /* write - bad */
- isofs_readdir, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* fsync */
+ readdir: isofs_readdir,
};
/*
@@ -48,21 +39,6 @@ struct inode_operations isofs_dir_inode_operations =
&isofs_dir_operations, /* default directory file-ops */
NULL, /* create */
isofs_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
static int isofs_name_translate(char * old, int len, char * new)
diff --git a/fs/isofs/file.c b/fs/isofs/file.c
index b15b6c5dc..9de31e024 100644
--- a/fs/isofs/file.c
+++ b/fs/isofs/file.c
@@ -22,36 +22,10 @@
* the isofs filesystem.
*/
static struct file_operations isofs_file_operations = {
- NULL, /* lseek - default */
- generic_file_read, /* read */
- NULL, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- generic_file_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- NULL, /* release */
- NULL /* fsync */
+ read: generic_file_read,
+ mmap: generic_file_mmap,
};
struct inode_operations isofs_file_inode_operations = {
&isofs_file_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- isofs_get_block, /* get_block */
- block_read_full_page, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index d14c18071..2c67d9e5a 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -1006,6 +1006,19 @@ int isofs_bmap(struct inode *inode, int block)
return 0;
}
+static int isofs_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,isofs_get_block);
+}
+static int _isofs_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,isofs_get_block);
+}
+static struct address_space_operations isofs_aops = {
+ readpage: isofs_readpage,
+ bmap: _isofs_bmap
+};
+
static void test_and_set_uid(uid_t *p, uid_t value)
{
if(value) {
@@ -1254,13 +1267,15 @@ static void isofs_read_inode(struct inode * inode)
} else
#endif IGNORE_WRONG_MULTI_VOLUME_SPECS
{
- if (S_ISREG(inode->i_mode))
+ if (S_ISREG(inode->i_mode)) {
inode->i_op = &isofs_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
+ inode->i_data.a_ops = &isofs_aops;
+ } else if (S_ISDIR(inode->i_mode))
inode->i_op = &isofs_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &isofs_symlink_inode_operations;
- else
+ else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_data.a_ops = &isofs_symlink_aops;
+ } else
/* XXX - parse_rock_ridge_inode() had already set i_rdev. */
init_special_inode(inode, inode->i_mode, kdev_t_to_nr(inode->i_rdev));
}
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index 814d90b3c..71be5edd1 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -445,7 +445,7 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr)
/* readpage() for symlinks: reads symlink contents into the page and either
makes it uptodate and returns 0 or returns error (-EIO) */
-int rock_ridge_symlink_readpage(struct dentry *dentry, struct page *page)
+static int rock_ridge_symlink_readpage(struct dentry *dentry, struct page *page)
{
struct inode *inode = dentry->d_inode;
char *link = (char*)kmap(page);
@@ -540,3 +540,7 @@ int rock_ridge_symlink_readpage(struct dentry *dentry, struct page *page)
UnlockPage(page);
return -EIO;
}
+
+struct address_space_operations isofs_symlink_aops = {
+ readpage: rock_ridge_symlink_readpage
+};
diff --git a/fs/isofs/symlink.c b/fs/isofs/symlink.c
deleted file mode 100644
index 219a4b9ac..000000000
--- a/fs/isofs/symlink.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * linux/fs/isofs/symlink.c
- *
- * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem.
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * isofs symlink handling code. This is only used with the Rock Ridge
- * extensions to iso9660
- */
-
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/iso_fs.h>
-#include <linux/stat.h>
-#include <linux/malloc.h>
-
-/*
- * symlinks can't do much...
- */
-struct inode_operations isofs_symlink_inode_operations = {
- readlink: page_readlink,
- follow_link: page_follow_link,
- readpage: rock_ridge_symlink_readpage
-};
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 878797b8a..e22007445 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -308,13 +308,13 @@ out:
#ifdef MODULE
/* New module support in 2.1.18 */
-#if LINUX_VERSION_CODE >= 0x020112
- EXPORT_NO_SYMBOLS;
- MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
- MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION ".");
- MODULE_PARM(nlm_grace_period, "10-240l");
- MODULE_PARM(nlm_timeout, "3-20l");
-#endif
+
+EXPORT_NO_SYMBOLS;
+MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
+MODULE_DESCRIPTION("NFS file locking service version " LOCKD_VERSION ".");
+MODULE_PARM(nlm_grace_period, "10-240l");
+MODULE_PARM(nlm_timeout, "3-20l");
+
int
init_module(void)
{
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index cb090cfd3..0902eaa0d 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -95,8 +95,8 @@ nlm_decode_fh(u32 *p, struct nfs_fh *f)
if ((len = ntohl(*p++)) != sizeof(*f)) {
printk(KERN_NOTICE
- "lockd: bad fhandle size %u (should be %lu)\n",
- len, (unsigned long) sizeof(*f));
+ "lockd: bad fhandle size %x (should be %Zu)\n",
+ len, sizeof(*f));
return NULL;
}
memcpy(f, p, sizeof(*f));
diff --git a/fs/minix/Makefile b/fs/minix/Makefile
index 537127b2d..c3aee4fe3 100644
--- a/fs/minix/Makefile
+++ b/fs/minix/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile.
O_TARGET := minix.o
-O_OBJS := bitmap.o truncate.o namei.o inode.o file.o dir.o symlink.o fsync.o
+O_OBJS := bitmap.o truncate.o namei.o inode.o file.o dir.o fsync.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 52c0e0cee..02bde162d 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -23,17 +23,9 @@ static ssize_t minix_dir_read(struct file * filp, char * buf,
static int minix_readdir(struct file *, void *, filldir_t);
static struct file_operations minix_dir_operations = {
- NULL, /* lseek - default */
- minix_dir_read, /* read */
- NULL, /* write - bad */
- minix_readdir, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- file_fsync /* default fsync */
+ read: minix_dir_read,
+ readdir: minix_readdir,
+ fsync: file_fsync,
};
/*
@@ -50,14 +42,6 @@ struct inode_operations minix_dir_inode_operations = {
minix_rmdir, /* rmdir */
minix_mknod, /* mknod */
minix_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
static int minix_readdir(struct file * filp,
diff --git a/fs/minix/file.c b/fs/minix/file.c
index 6445c225c..61d0e3f02 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -18,60 +18,21 @@
#include <asm/uaccess.h>
#include <asm/system.h>
-#define NBUF 32
-
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-
#include <linux/fs.h>
#include <linux/minix_fs.h>
/*
- * Write to a file (through the page cache).
- */
-static ssize_t
-minix_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
-{
- return generic_file_write(file, buf, count,
- ppos, block_write_partial_page);
-}
-
-/*
* We have mostly NULLs here: the current defaults are OK for
* the minix filesystem.
*/
static struct file_operations minix_file_operations = {
- NULL, /* lseek - default */
- generic_file_read, /* read */
- minix_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- generic_file_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- NULL, /* release */
- minix_sync_file, /* fsync */
- NULL, /* fasync */
+ read: generic_file_read,
+ write: generic_file_write,
+ mmap: generic_file_mmap,
+ fsync: minix_sync_file,
};
struct inode_operations minix_file_inode_operations = {
- &minix_file_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- minix_get_block, /* get_block */
- block_read_full_page, /* readpage */
- block_write_full_page, /* writepage */
- minix_truncate, /* truncate */
- NULL, /* permission */
- NULL, /* revalidate */
+ &minix_file_operations,
+ truncate: minix_truncate,
};
diff --git a/fs/minix/fsync.c b/fs/minix/fsync.c
index 2fcdddf15..30794d27a 100644
--- a/fs/minix/fsync.c
+++ b/fs/minix/fsync.c
@@ -16,6 +16,7 @@
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/locks.h>
+#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <linux/minix_fs.h>
@@ -148,10 +149,7 @@ static int V1_minix_sync_file(struct inode * inode, struct file * file)
{
int wait, err = 0;
- if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)))
- return -EINVAL;
-
+ lock_kernel();
for (wait=0; wait<=1; wait++)
{
err |= V1_sync_direct(inode, wait);
@@ -159,6 +157,7 @@ static int V1_minix_sync_file(struct inode * inode, struct file * file)
err |= V1_sync_dindirect(inode, inode->u.minix_i.u.i1_data + 8, wait);
}
err |= minix_sync_inode (inode);
+ unlock_kernel();
return (err < 0) ? -EIO : 0;
}
@@ -309,10 +308,7 @@ static int V2_minix_sync_file(struct inode * inode, struct file * file)
{
int wait, err = 0;
- if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)))
- return -EINVAL;
-
+ lock_kernel();
for (wait=0; wait<=1; wait++)
{
err |= V2_sync_direct(inode, wait);
@@ -324,6 +320,7 @@ static int V2_minix_sync_file(struct inode * inode, struct file * file)
(unsigned long *) inode->u.minix_i.u.i2_data + 9, wait);
}
err |= minix_sync_inode (inode);
+ unlock_kernel();
return (err < 0) ? -EIO : 0;
}
@@ -336,6 +333,10 @@ int minix_sync_file(struct file * file, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)))
+ return -EINVAL;
+
if (INODE_VERSION(inode) == MINIX_V1)
return V1_minix_sync_file(inode, file);
else
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index de093d02f..e33fe9787 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -968,7 +968,7 @@ abort_too_big:
goto abort;
}
-int minix_get_block(struct inode *inode, long block,
+static int minix_get_block(struct inode *inode, long block,
struct buffer_head *bh_result, int create)
{
if (INODE_VERSION(inode) == MINIX_V1)
@@ -1016,6 +1016,30 @@ struct buffer_head * minix_bread(struct inode * inode, int block, int create)
return NULL;
}
+static int minix_writepage(struct dentry *dentry, struct page *page)
+{
+ return block_write_full_page(page,minix_get_block);
+}
+static int minix_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,minix_get_block);
+}
+static int minix_prepare_write(struct page *page, unsigned from, unsigned to)
+{
+ return block_prepare_write(page,from,to,minix_get_block);
+}
+static int minix_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,minix_get_block);
+}
+struct address_space_operations minix_aops = {
+ readpage: minix_readpage,
+ writepage: minix_writepage,
+ prepare_write: minix_prepare_write,
+ commit_write: generic_commit_write,
+ bmap: minix_bmap
+};
+
/*
* The minix V1 function to read an inode.
*/
@@ -1053,13 +1077,15 @@ static void V1_minix_read_inode(struct inode * inode)
inode->i_blocks = inode->i_blksize = 0;
for (block = 0; block < 9; block++)
inode->u.minix_i.u.i1_data[block] = raw_inode->i_zone[block];
- if (S_ISREG(inode->i_mode))
+ if (S_ISREG(inode->i_mode)) {
inode->i_op = &minix_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
+ inode->i_mapping->a_ops = &minix_aops;
+ } else if (S_ISDIR(inode->i_mode))
inode->i_op = &minix_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &minix_symlink_inode_operations;
- else
+ else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_mapping->a_ops = &minix_aops;
+ } else
init_special_inode(inode, inode->i_mode, raw_inode->i_zone[0]);
brelse(bh);
}
@@ -1103,13 +1129,15 @@ static void V2_minix_read_inode(struct inode * inode)
inode->i_blocks = inode->i_blksize = 0;
for (block = 0; block < 10; block++)
inode->u.minix_i.u.i2_data[block] = raw_inode->i_zone[block];
- if (S_ISREG(inode->i_mode))
+ if (S_ISREG(inode->i_mode)) {
inode->i_op = &minix_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
+ inode->i_mapping->a_ops = &minix_aops;
+ } else if (S_ISDIR(inode->i_mode))
inode->i_op = &minix_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &minix_symlink_inode_operations;
- else
+ else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_mapping->a_ops = &minix_aops;
+ } else
init_special_inode(inode, inode->i_mode, raw_inode->i_zone[0]);
brelse(bh);
}
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index a3e73dbcd..de2d0f279 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -219,6 +219,7 @@ int minix_create(struct inode * dir, struct dentry *dentry, int mode)
if (!inode)
return -ENOSPC;
inode->i_op = &minix_file_inode_operations;
+ inode->i_mapping->a_ops = &minix_aops;
inode->i_mode = mode;
mark_inode_dirty(inode);
error = minix_add_entry(dir, dentry->d_name.name,
@@ -477,7 +478,8 @@ int minix_symlink(struct inode * dir, struct dentry *dentry,
goto out;
inode->i_mode = S_IFLNK | 0777;
- inode->i_op = &minix_symlink_inode_operations;
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_mapping->a_ops = &minix_aops;
err = block_symlink(inode, symname, i);
if (err)
goto fail;
diff --git a/fs/minix/symlink.c b/fs/minix/symlink.c
deleted file mode 100644
index 7e1d03a10..000000000
--- a/fs/minix/symlink.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * linux/fs/minix/symlink.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * minix symlink handling code
- *
- * Code removed. 1999, AV ;-)
- */
-
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
-
-/*
- * symlinks can't do much...
- */
-struct inode_operations minix_symlink_inode_operations = {
- readlink: page_readlink,
- follow_link: page_follow_link,
- get_block: minix_get_block,
- readpage: block_read_full_page
-};
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index ea0b05616..155489072 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -595,14 +595,6 @@ struct inode_operations msdos_dir_inode_operations = {
msdos_rmdir, /* rmdir */
NULL, /* mknod */
msdos_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* revalidate */
};
static void msdos_put_super_callback(struct super_block *sb)
diff --git a/fs/namei.c b/fs/namei.c
index 3b0b73686..102f0e432 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1386,8 +1386,8 @@ unsigned int follow, const char *link)
static char *page_getlink(struct dentry * dentry, struct page **ppage)
{
struct page * page;
- page = read_cache_page(&dentry->d_inode->i_data, 0,
- (filler_t *)dentry->d_inode->i_op->readpage,
+ struct address_space *mapping = dentry->d_inode->i_mapping;
+ page = read_cache_page(mapping, 0, (filler_t *)mapping->a_ops->readpage,
dentry);
if (IS_ERR(page))
goto sync_fail;
@@ -1429,3 +1429,8 @@ page_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow
}
return res;
}
+
+struct inode_operations page_symlink_inode_operations = {
+ readlink: page_readlink,
+ follow_link: page_follow_link,
+};
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 565f88c5b..e5e91a24c 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -47,17 +47,9 @@ extern int ncp_symlink(struct inode *, struct dentry *, const char *);
static struct file_operations ncp_dir_operations =
{
- NULL, /* lseek - default */
- ncp_dir_read, /* read - bad */
- NULL, /* write - bad */
- ncp_readdir, /* readdir */
- NULL, /* poll - default */
- ncp_ioctl, /* ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* fsync */
+ read: ncp_dir_read,
+ readdir: ncp_readdir,
+ ioctl: ncp_ioctl,
};
struct inode_operations ncp_dir_inode_operations =
@@ -78,9 +70,6 @@ struct inode_operations ncp_dir_inode_operations =
ncp_rename, /* rename */
NULL, /* readlink */
NULL, /* follow link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* revalidate */
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 5e28516bf..09b95cd4f 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -277,17 +277,11 @@ out:
static struct file_operations ncp_file_operations =
{
- NULL, /* lseek - default */
- ncp_file_read, /* read */
- ncp_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- ncp_ioctl, /* ioctl */
- ncp_mmap, /* mmap */
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- ncp_fsync, /* fsync */
+ read: ncp_file_read,
+ write: ncp_file_write,
+ ioctl: ncp_ioctl,
+ mmap: ncp_mmap,
+ fsync: ncp_fsync,
};
struct inode_operations ncp_file_inode_operations =
@@ -304,9 +298,6 @@ struct inode_operations ncp_file_inode_operations =
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
NULL, /* truncate */
NULL, /* permission */
NULL /* revalidate */
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 84b9e5643..5a4e790a7 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -51,7 +51,7 @@ static struct super_operations ncp_sops =
extern struct dentry_operations ncp_dentry_operations;
#ifdef CONFIG_NCPFS_EXTRAS
-extern struct inode_operations ncp_symlink_inode_operations;
+extern struct address_space_operations ncp_symlink_aops;
extern int ncp_symlink(struct inode*, struct dentry*, const char*);
#endif
@@ -226,7 +226,8 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
inode->i_op = &ncp_dir_inode_operations;
#ifdef CONFIG_NCPFS_EXTRAS
} else if (S_ISLNK(inode->i_mode)) {
- inode->i_op = &ncp_symlink_inode_operations;
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_data.a_ops = &ncp_symlink_aops;
#endif
}
insert_inode_hash(inode);
diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
index 5e5bf2fbd..b0bc34b22 100644
--- a/fs/ncpfs/symlink.c
+++ b/fs/ncpfs/symlink.c
@@ -96,9 +96,7 @@ fail:
/*
* symlinks can't do much...
*/
-struct inode_operations ncp_symlink_inode_operations={
- readlink: page_readlink,
- follow_link: page_follow_link,
+struct address_space_operations ncp_symlink_aops = {
readpage: ncp_symlink_readpage,
};
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 788307cc2..82d3f5bc3 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -52,17 +52,10 @@ static int nfs_rename(struct inode *, struct dentry *,
struct inode *, struct dentry *);
static struct file_operations nfs_dir_operations = {
- NULL, /* lseek - default */
- nfs_dir_read, /* read - bad */
- NULL, /* write - bad */
- nfs_readdir, /* readdir */
- NULL, /* select - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- nfs_open, /* open */
- NULL, /* flush */
- nfs_release, /* release */
- NULL /* fsync */
+ read: nfs_dir_read,
+ readdir: nfs_readdir,
+ open: nfs_open,
+ release: nfs_release,
};
struct inode_operations nfs_dir_inode_operations = {
@@ -78,9 +71,6 @@ struct inode_operations nfs_dir_inode_operations = {
nfs_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
NULL, /* truncate */
NULL, /* permission */
nfs_revalidate, /* revalidate */
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index f687cfdab..2135ece68 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -41,19 +41,14 @@ static int nfs_file_flush(struct file *);
static int nfs_fsync(struct file *, struct dentry *dentry);
static struct file_operations nfs_file_operations = {
- NULL, /* lseek - default */
- nfs_file_read, /* read */
- nfs_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* select - default */
- NULL, /* ioctl - default */
- nfs_file_mmap, /* mmap */
- nfs_open, /* open */
- nfs_file_flush, /* flush */
- nfs_release, /* release */
- nfs_fsync, /* fsync */
- NULL, /* fasync */
- nfs_lock, /* lock */
+ read: nfs_file_read,
+ write: nfs_file_write,
+ mmap: nfs_file_mmap,
+ open: nfs_open,
+ flush: nfs_file_flush,
+ release: nfs_release,
+ fsync: nfs_fsync,
+ lock: nfs_lock,
};
struct inode_operations nfs_file_inode_operations = {
@@ -69,9 +64,6 @@ struct inode_operations nfs_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* get_block */
- nfs_readpage, /* readpage */
- nfs_writepage, /* writepage */
NULL, /* truncate */
NULL, /* permission */
nfs_revalidate, /* revalidate */
@@ -146,11 +138,13 @@ nfs_fsync(struct file *file, struct dentry *dentry)
dfprintk(VFS, "nfs: fsync(%x/%ld)\n", inode->i_dev, inode->i_ino);
+ lock_kernel();
status = nfs_wb_file(inode, file);
if (!status) {
status = file->f_error;
file->f_error = 0;
}
+ unlock_kernel();
return status;
}
@@ -163,21 +157,29 @@ nfs_fsync(struct file *file, struct dentry *dentry)
* If the writer ends up delaying the write, the writer needs to
* increment the page use counts until he is done with the page.
*/
-static int nfs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+static int nfs_prepare_write(struct page *page, unsigned offset, unsigned to)
+{
+ kmap(page);
+ return 0;
+}
+static int nfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
long status;
- bytes -= copy_from_user((u8*)kmap(page) + offset, buf, bytes);
kunmap(page);
- status = -EFAULT;
- if (bytes) {
- lock_kernel();
- status = nfs_updatepage(file, page, offset, bytes);
- unlock_kernel();
- }
+ lock_kernel();
+ status = nfs_updatepage(file, page, offset, to-offset);
+ unlock_kernel();
return status;
}
+struct address_space_operations nfs_file_aops = {
+ readpage: nfs_readpage,
+ writepage: nfs_writepage,
+ prepare_write: nfs_prepare_write,
+ commit_write: nfs_commit_write
+};
+
/*
* Write to a file (through the page cache).
*/
@@ -203,7 +205,7 @@ nfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
if (!count)
goto out;
- result = generic_file_write(file, buf, count, ppos, nfs_write_one_page);
+ result = generic_file_write(file, buf, count, ppos);
out:
return result;
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index aae8d3d0a..c8d42adfe 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -473,9 +473,10 @@ nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
NFS_FILEID(inode) = fattr->fileid;
NFS_FSID(inode) = fattr->fsid;
inode->i_mode = fattr->mode;
- if (S_ISREG(inode->i_mode))
+ if (S_ISREG(inode->i_mode)) {
inode->i_op = &nfs_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
+ inode->i_data.a_ops = &nfs_file_aops;
+ } else if (S_ISDIR(inode->i_mode))
inode->i_op = &nfs_dir_inode_operations;
else if (S_ISLNK(inode->i_mode))
inode->i_op = &nfs_symlink_inode_operations;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 09a16b302..a13e26fd0 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -479,7 +479,7 @@ updated:
if (req->wb_bytes == PAGE_SIZE)
SetPageUptodate(page);
- retval = count;
+ retval = 0;
if (synchronous) {
int status = wait_on_write_request(req);
if (status) {
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 68e7a1dac..b0aac3280 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -29,13 +29,7 @@
#include <linux/nfsd/xdr.h>
#include <linux/nfsd/syscall.h>
-#if LINUX_VERSION_CODE >= 0x020100
#include <asm/uaccess.h>
-#else
-# define copy_from_user memcpy_fromfs
-# define copy_to_user memcpy_tofs
-# define access_ok !verify_area
-#endif
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -249,10 +243,8 @@ done:
#ifdef MODULE
/* New-style module support since 2.1.18 */
-#if LINUX_VERSION_CODE >= 131346
EXPORT_NO_SYMBOLS;
MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
-#endif
extern int (*do_nfsservctl)(int, void *, void *);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 95bec2fc5..b1af9399e 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -39,9 +39,7 @@
#include <linux/nfsd/nfsfh.h>
#include <linux/quotaops.h>
-#if LINUX_VERSION_CODE >= 0x020100
#include <asm/uaccess.h>
-#endif
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
#define NFSD_PARANOIA
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index 7de7eb5c4..fff05ca9b 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -405,44 +405,14 @@ static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d)
}
static struct file_operations ntfs_file_operations_nommap = {
- NULL, /* lseek */
- ntfs_read,
+ read: ntfs_read,
#ifdef CONFIG_NTFS_RW
- ntfs_write,
-#else
- NULL,
+ write: ntfs_write,
#endif
- NULL, /* readdir */
- NULL, /* select */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
};
static struct inode_operations ntfs_inode_operations_nobmap = {
&ntfs_file_operations_nommap,
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* revalidate */
};
#ifdef CONFIG_NTFS_RW
@@ -583,52 +553,28 @@ ntfs_bmap(struct inode *ino,int block)
return (ret==-1) ? 0:ret;
}
+/* It's fscking broken. */
+
+static int ntfs_get_block(struct inode *inode, long block, struct buffer_head *bh, int create)
+{
+ BUG();
+ return -1;
+}
+
static struct file_operations ntfs_file_operations = {
- NULL, /* lseek */
- ntfs_read,
+ read: ntfs_read,
+ mmap: generic_file_mmap,
#ifdef CONFIG_NTFS_RW
- ntfs_write,
-#else
- NULL,
+ write: ntfs_write,
#endif
- NULL, /* readdir */
- NULL, /* select */
- NULL, /* ioctl */
- generic_file_mmap,
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
- NULL, /* lock */
};
static struct inode_operations ntfs_inode_operations = {
&ntfs_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 */
- ntfs_bmap, /* get_block */
- block_read_full_page, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* revalidate */
};
static struct file_operations ntfs_dir_operations = {
- NULL, /* lseek */
- NULL, /* read */
- NULL, /* write */
- ntfs_readdir, /* readdir */
+ readdir: ntfs_readdir,
};
static struct inode_operations ntfs_dir_inode_operations = {
@@ -650,16 +596,32 @@ static struct inode_operations ntfs_dir_inode_operations = {
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* revalidate */
};
+static int ntfs_writepage(struct dentry *dentry, struct page *page)
+{
+ return block_write_full_page(page,ntfs_get_block);
+}
+static int ntfs_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,ntfs_get_block);
+}
+static int ntfs_prepare_write(struct page *page, unsigned from, unsigned to)
+{
+ return cont_prepare_write(page,from,to,ntfs_get_block,
+ &((struct inode*)page->mapping->host)->u.ntfs_i.mmu_private);
+}
+static int _ntfs_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,ntfs_get_block);
+}
+struct address_space_operations ntfs_aops = {
+ readpage: ntfs_readpage,
+ writepage: ntfs_writepage,
+ prepare_write: ntfs_prepare_write,
+ commit_write: generic_commit_write,
+ bmap: _ntfs_bmap
+};
/* ntfs_read_inode is called by the Virtual File System (the kernel layer that
* deals with filesystems) when iget is called requesting an inode not already
* present in the inode table. Typically filesystems have separate
@@ -735,8 +697,13 @@ static void ntfs_read_inode(struct inode* inode)
}
else
{
- inode->i_op=can_mmap ? &ntfs_inode_operations :
- &ntfs_inode_operations_nobmap;
+ if (can_mmap) {
+ inode->i_op = &ntfs_inode_operations;
+ inode->i_mapping->a_ops = &ntfs_aops;
+ inode->u.ntfs_i.mmu_private = inode->i_size;
+ } else {
+ inode->i_op=&ntfs_inode_operations_nobmap;
+ }
inode->i_mode=S_IFREG|S_IRUGO;
}
#ifdef CONFIG_NTFS_RW
diff --git a/fs/open.c b/fs/open.c
index 8aa828088..159b08bf7 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -898,16 +898,9 @@ asmlinkage long sys_close(unsigned int fd)
*/
asmlinkage long sys_vhangup(void)
{
- int ret = -EPERM;
-
- if (!capable(CAP_SYS_TTY_CONFIG))
- goto out;
- /* If there is a controlling tty, hang it up */
- lock_kernel();
- if (current->tty)
+ if (capable(CAP_SYS_TTY_CONFIG)) {
tty_vhangup(current->tty);
- unlock_kernel();
- ret = 0;
-out:
- return ret;
+ return 0;
+ }
+ return -EPERM;
}
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index b09462b89..710c8a7dd 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -1,4 +1,4 @@
-/* $Id: inode.c,v 1.3 2000/01/04 10:02:29 jj Exp $
+/* $Id: inode.c,v 1.4 2000/02/09 22:35:50 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
* Copyright (C) 1996-1999 Jakub Jelinek (jakub@redhat.com)
@@ -553,17 +553,9 @@ int property_release (struct inode *inode, struct file *filp)
}
static struct file_operations openpromfs_prop_ops = {
- NULL, /* lseek - default */
- property_read, /* read */
- property_write, /* write - bad */
- NULL, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- property_release, /* no special release code */
- NULL /* can't fsync */
+ read: property_read,
+ write: property_write,
+ release: property_release,
};
static struct inode_operations openpromfs_prop_inode_ops = {
@@ -571,17 +563,7 @@ static struct inode_operations openpromfs_prop_inode_ops = {
};
static struct file_operations openpromfs_nodenum_ops = {
- NULL, /* lseek - default */
- nodenum_read, /* read */
- NULL, /* write - bad */
- NULL, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
+ read: nodenum_read,
};
static struct inode_operations openpromfs_nodenum_inode_ops = {
@@ -589,17 +571,7 @@ static struct inode_operations openpromfs_nodenum_inode_ops = {
};
static struct file_operations openprom_alias_operations = {
- NULL, /* lseek - default */
- NULL, /* read - bad */
- NULL, /* write - bad */
- openpromfs_readdir, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
+ readdir: openpromfs_readdir,
};
static struct inode_operations openprom_alias_inode_operations = {
@@ -608,19 +580,6 @@ static struct inode_operations openprom_alias_inode_operations = {
openpromfs_lookup, /* lookup */
NULL, /* link */
openpromfs_unlink, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
extern struct inode_operations openprom_inode_operations;
@@ -1019,10 +978,7 @@ static u16 get_nodes (u16 parent, u32 node)
static struct file_operations openprom_operations = {
- NULL, /* lseek - default */
- NULL, /* read - bad */
- NULL, /* write - bad */
- openpromfs_readdir, /* readdir */
+ readdir: openpromfs_readdir,
};
static struct inode_operations openprom_inode_operations = {
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index d9c4c11de..4f6cfd07d 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -18,6 +18,7 @@
#include <linux/major.h>
#include <linux/blk.h>
#include <linux/init.h>
+#include <linux/raid/md.h>
#include "check.h"
@@ -317,6 +318,9 @@ int __init partition_setup(void)
#endif
rd_load();
#endif
+#ifdef CONFIG_BLK_DEV_MD
+ autodetect_raid();
+#endif
#ifdef CONFIG_MD_BOOT
md_setup_drive();
#endif
diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c
index 41364385d..119de17ba 100644
--- a/fs/partitions/mac.c
+++ b/fs/partitions/mac.c
@@ -28,6 +28,14 @@ extern void note_bootable_part(kdev_t dev, int part);
* Code to understand MacOS partition tables.
*/
+static inline void mac_fix_string(char *stg, int len)
+{
+ int i;
+
+ for (i = len - 1; i >= 0 && stg[i] == ' '; i--)
+ stg[i] = 0;
+}
+
int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_part_minor)
{
struct buffer_head *bh;
@@ -35,7 +43,8 @@ int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_
int dev_bsize, dev_pos, pos;
unsigned secsize;
#ifdef CONFIG_PPC
- int first_bootable = 1;
+ int found_root = 0;
+ int found_root_goodness = 0;
#endif
struct mac_partition *part;
struct mac_driver_desc *md;
@@ -93,16 +102,49 @@ int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec, int first_
* If this is the first bootable partition, tell the
* setup code, in case it wants to make this the root.
*/
- if ( (_machine == _MACH_Pmac) && first_bootable
- && (be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
- && strcasecmp(part->processor, "powerpc") == 0) {
- note_bootable_part(dev, blk);
- first_bootable = 0;
+ if (_machine == _MACH_Pmac) {
+ int goodness = 0;
+
+ mac_fix_string(part->processor, 16);
+ mac_fix_string(part->name, 32);
+ mac_fix_string(part->type, 32);
+
+ if ((be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
+ && strcasecmp(part->processor, "powerpc") == 0)
+ goodness++;
+
+ if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
+ || strcasecmp(part->type, "Linux_PPC") == 0) {
+ int i, l;
+
+ goodness++;
+ l = strlen(part->name);
+ if (strcmp(part->name, "/") == 0)
+ goodness++;
+ for (i = 0; i <= l - 4; ++i) {
+ if (strnicmp(part->name + i, "root",
+ 4) == 0) {
+ goodness += 2;
+ break;
+ }
+ }
+ if (strnicmp(part->name, "swap", 4) == 0)
+ goodness--;
+ }
+
+ if (goodness > found_root_goodness) {
+ found_root = blk;
+ found_root_goodness = goodness;
+ }
}
#endif /* CONFIG_PPC */
++first_part_minor;
}
+#ifdef CONFIG_PPC
+ if (found_root_goodness)
+ note_bootable_part(dev, found_root);
+#endif
brelse(bh);
printk("\n");
return 1;
diff --git a/fs/pipe.c b/fs/pipe.c
index 68922b9b8..2dea69d60 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -462,101 +462,73 @@ pipe_rdwr_open(struct inode *inode, struct file *filp)
* are also used in linux/fs/fifo.c to do operations on FIFOs.
*/
struct file_operations connecting_fifo_fops = {
- pipe_lseek,
- connect_read,
- bad_pipe_w,
- NULL, /* no readdir */
- connect_poll,
- pipe_ioctl,
- NULL, /* no mmap on pipes.. surprise */
- pipe_read_open,
- NULL, /* flush */
- pipe_read_release,
- NULL
+ llseek: pipe_lseek,
+ read: connect_read,
+ write: bad_pipe_w,
+ poll: connect_poll,
+ ioctl: pipe_ioctl,
+ open: pipe_read_open,
+ release: pipe_read_release,
};
struct file_operations read_fifo_fops = {
- pipe_lseek,
- pipe_read,
- bad_pipe_w,
- NULL, /* no readdir */
- fifo_poll,
- pipe_ioctl,
- NULL, /* no mmap on pipes.. surprise */
- pipe_read_open,
- NULL, /* flush */
- pipe_read_release,
- NULL
+ llseek: pipe_lseek,
+ read: pipe_read,
+ write: bad_pipe_w,
+ poll: fifo_poll,
+ ioctl: pipe_ioctl,
+ open: pipe_read_open,
+ release: pipe_read_release,
};
struct file_operations write_fifo_fops = {
- pipe_lseek,
- bad_pipe_r,
- pipe_write,
- NULL, /* no readdir */
- fifo_poll,
- pipe_ioctl,
- NULL, /* mmap */
- pipe_write_open,
- NULL, /* flush */
- pipe_write_release,
- NULL
+ llseek: pipe_lseek,
+ read: bad_pipe_r,
+ write: pipe_write,
+ poll: fifo_poll,
+ ioctl: pipe_ioctl,
+ open: pipe_write_open,
+ release: pipe_write_release,
};
struct file_operations rdwr_fifo_fops = {
- pipe_lseek,
- pipe_read,
- pipe_write,
- NULL, /* no readdir */
- fifo_poll,
- pipe_ioctl,
- NULL, /* mmap */
- pipe_rdwr_open,
- NULL, /* flush */
- pipe_rdwr_release,
- NULL
+ llseek: pipe_lseek,
+ read: pipe_read,
+ write: pipe_write,
+ poll: fifo_poll,
+ ioctl: pipe_ioctl,
+ open: pipe_rdwr_open,
+ release: pipe_rdwr_release,
};
struct file_operations read_pipe_fops = {
- pipe_lseek,
- pipe_read,
- bad_pipe_w,
- NULL, /* no readdir */
- pipe_poll,
- pipe_ioctl,
- NULL, /* no mmap on pipes.. surprise */
- pipe_read_open,
- NULL, /* flush */
- pipe_read_release,
- NULL
+ llseek: pipe_lseek,
+ read: pipe_read,
+ write: bad_pipe_w,
+ poll: pipe_poll,
+ ioctl: pipe_ioctl,
+ open: pipe_read_open,
+ release: pipe_read_release,
};
struct file_operations write_pipe_fops = {
- pipe_lseek,
- bad_pipe_r,
- pipe_write,
- NULL, /* no readdir */
- pipe_poll,
- pipe_ioctl,
- NULL, /* mmap */
- pipe_write_open,
- NULL, /* flush */
- pipe_write_release,
- NULL
+ llseek: pipe_lseek,
+ read: bad_pipe_r,
+ write: pipe_write,
+ poll: pipe_poll,
+ ioctl: pipe_ioctl,
+ open: pipe_write_open,
+ release: pipe_write_release,
};
struct file_operations rdwr_pipe_fops = {
- pipe_lseek,
- pipe_read,
- pipe_write,
- NULL, /* no readdir */
- pipe_poll,
- pipe_ioctl,
- NULL, /* mmap */
- pipe_rdwr_open,
- NULL, /* flush */
- pipe_rdwr_release,
- NULL
+ llseek: pipe_lseek,
+ read: pipe_read,
+ write: pipe_write,
+ poll: pipe_poll,
+ ioctl: pipe_ioctl,
+ open: pipe_rdwr_open,
+ release: pipe_rdwr_release,
};
static struct inode * get_pipe_inode(void)
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index fade4acf2..ad890255e 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -10,9 +10,6 @@
O_TARGET := proc.o
O_OBJS := inode.o root.o base.o generic.o array.o \
kmsg.o proc_tty.o proc_misc.o kcore.o
-ifdef CONFIG_OMIRR
-O_OBJS := $(O_OBJS) omirr.o
-endif
OX_OBJS := procfs_syms.o
M_OBJS :=
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 4ae097ca2..65bc80c88 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -133,8 +133,7 @@ static inline const char * get_task_state(struct task_struct *tsk)
TASK_INTERRUPTIBLE |
TASK_UNINTERRUPTIBLE |
TASK_ZOMBIE |
- TASK_STOPPED |
- TASK_SWAPPING);
+ TASK_STOPPED);
const char **p = &task_state_array[0];
while (state) {
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 4670b456c..cdd2116b2 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -15,7 +15,6 @@
#include <asm/uaccess.h>
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
@@ -206,8 +205,7 @@ static ssize_t pid_maps_read(struct file * file, char * buf,
}
static struct file_operations proc_maps_operations = {
- NULL, /* array_lseek */
- pid_maps_read,
+ read: pid_maps_read,
};
struct inode_operations proc_maps_inode_operations = {
@@ -258,8 +256,7 @@ static ssize_t proc_info_read(struct file * file, char * buf,
}
static struct file_operations proc_info_file_operations = {
- NULL, /* lseek */
- proc_info_read, /* read */
+ read: proc_info_read,
};
static struct inode_operations proc_info_inode_operations = {
@@ -348,9 +345,8 @@ static ssize_t mem_write(struct file * file, const char * buf,
}
static struct file_operations proc_mem_operations = {
- NULL, /* lseek - default */
- mem_read,
- mem_write,
+ read: mem_read,
+ write: mem_write,
};
static struct inode_operations proc_mem_inode_operations = {
@@ -366,9 +362,6 @@ static struct inode_operations proc_mem_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
NULL, /* truncate */
proc_permission, /* permission */
NULL /* revalidate */
@@ -456,18 +449,8 @@ out:
}
static struct inode_operations proc_pid_link_inode_operations = {
- NULL, /* file-operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- proc_pid_readlink, /* readlink */
- proc_pid_follow_link, /* follow_link */
+ readlink: proc_pid_readlink,
+ follow_link: proc_pid_follow_link
};
/* reading from directory - bad */
@@ -761,10 +744,8 @@ out:
}
static struct file_operations proc_fd_operations = {
- NULL, /* lseek - default */
- proc_dir_read, /* read - bad */
- NULL, /* write - bad */
- proc_readfd, /* readdir */
+ read: proc_dir_read, /* read - bad */
+ readdir: proc_readfd, /* readdir */
};
/*
@@ -783,9 +764,6 @@ static struct inode_operations proc_fd_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
NULL, /* truncate */
proc_permission, /* permission */
};
@@ -882,10 +860,8 @@ out:
}
static struct file_operations proc_base_operations = {
- NULL, /* lseek - default */
- proc_dir_read, /* read - bad */
- NULL, /* write - bad */
- proc_base_readdir, /* readdir */
+ read: proc_dir_read, /* read - bad */
+ readdir: proc_base_readdir, /* readdir */
};
static struct inode_operations proc_base_inode_operations = {
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 3017323b2..ad42f4fbc 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -32,9 +32,9 @@ int proc_match(int len, const char *name,struct proc_dir_entry * de)
}
static struct file_operations proc_file_operations = {
- proc_file_lseek, /* lseek */
- proc_file_read, /* read */
- proc_file_write, /* write */
+ llseek: proc_file_lseek,
+ read: proc_file_read,
+ write: proc_file_write,
};
static struct inode_operations proc_file_inode_operations = {
@@ -337,10 +337,7 @@ int proc_readdir(struct file * filp,
* the /proc directory.
*/
static struct file_operations proc_dir_operations = {
- NULL, /* lseek - default */
- NULL, /* read - bad */
- NULL, /* write - bad */
- proc_readdir, /* readdir */
+ readdir: proc_readdir,
};
/*
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index f63bcac6e..01ac4fe2a 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -27,14 +27,8 @@ static int open_kcore(struct inode * inode, struct file * filp)
static ssize_t read_kcore(struct file *, char *, size_t, loff_t *);
static struct file_operations proc_kcore_operations = {
- NULL, /* lseek */
- read_kcore,
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- open_kcore
+ read: read_kcore,
+ open: open_kcore,
};
struct inode_operations proc_kcore_inode_operations = {
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c
index b9344ba55..a8fe0fc3c 100644
--- a/fs/proc/kmsg.c
+++ b/fs/proc/kmsg.c
@@ -46,17 +46,10 @@ static unsigned int kmsg_poll(struct file *file, poll_table * wait)
static struct file_operations proc_kmsg_operations = {
- NULL, /* kmsg_lseek */
- kmsg_read,
- NULL, /* kmsg_write */
- NULL, /* kmsg_readdir */
- kmsg_poll, /* kmsg_poll */
- NULL, /* kmsg_ioctl */
- NULL, /* mmap */
- kmsg_open,
- NULL, /* flush */
- kmsg_release,
- NULL /* can't fsync */
+ read: kmsg_read,
+ poll: kmsg_poll,
+ open: kmsg_open,
+ release: kmsg_release,
};
struct inode_operations proc_kmsg_inode_operations = {
diff --git a/fs/proc/omirr.c b/fs/proc/omirr.c
deleted file mode 100644
index bdbcb0cbf..000000000
--- a/fs/proc/omirr.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * fs/proc/omirr.c - online mirror support
- *
- * (C) 1997 Thomas Schoebel-Theuer
- */
-
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/omirr.h>
-#include <asm/uaccess.h>
-
-static int nr_omirr_open = 0;
-static int cleared_flag = 0;
-
-static char * buffer = NULL;
-static int read_pos, write_pos;
-static int clip_pos, max_pos;
-static DECLARE_WAIT_QUEUE_HEAD(read_wait);
-static DECLARE_WAIT_QUEUE_HEAD(write_wait);
-
-static /*inline*/ int reserve_write_space(int len)
-{
- int rest = max_pos - write_pos;
-
- if(rest < len) {
- clip_pos = write_pos;
- write_pos = 0;
- rest = max_pos;
- }
- while(read_pos > write_pos && read_pos <= write_pos+len) {
- if(!nr_omirr_open)
- return 0;
- interruptible_sleep_on(&write_wait);
- }
- return 1;
-}
-
-static /*inline*/ void write_space(int len)
-{
- write_pos += len;
- wake_up_interruptible(&read_wait);
-}
-
-static /*inline*/ int reserve_read_space(int len)
-{
- int rest = clip_pos - read_pos;
-
- if(!rest) {
- read_pos = 0;
- rest = clip_pos;
- clip_pos = max_pos;
- }
- if(len > rest)
- len = rest;
- while(read_pos == write_pos) {
- interruptible_sleep_on(&read_wait);
- }
- rest = write_pos - read_pos;
- if(rest > 0 && rest < len)
- len = rest;
- return len;
-}
-
-static /*inline*/ void read_space(int len)
-{
- read_pos += len;
- if(read_pos >= clip_pos) {
- read_pos = 0;
- clip_pos = max_pos;
- }
- wake_up_interruptible(&write_wait);
-}
-
-static /*inline*/ void init_buffer(char * initxt)
-{
- int len = initxt ? strlen(initxt) : 0;
-
- if(!buffer) {
- buffer = (char*)__get_free_page(GFP_USER);
- max_pos = clip_pos = PAGE_SIZE;
- }
- read_pos = write_pos = 0;
- memcpy(buffer, initxt, len);
- write_space(len);
-}
-
-static int omirr_open(struct inode * inode, struct file * file)
-{
- if(nr_omirr_open)
- return -EAGAIN;
- nr_omirr_open++;
- if(!buffer)
- init_buffer(NULL);
- return 0;
-}
-
-static int omirr_release(struct inode * inode, struct file * file)
-{
- nr_omirr_open--;
- read_space(0);
- return 0;
-}
-
-static long omirr_read(struct inode * inode, struct file * file,
- char * buf, unsigned long count)
-{
- char * tmp;
- int len;
- int error = 0;
-
- if(!count)
- goto done;
- error = -EINVAL;
- if(!buf || count < 0)
- goto done;
-
- error = verify_area(VERIFY_WRITE, buf, count);
- if(error)
- goto done;
-
- error = -EAGAIN;
- if((file->f_flags & O_NONBLOCK) && read_pos == write_pos)
- goto done;
-
- error = len = reserve_read_space(count);
- tmp = buffer + read_pos;
- while(len) {
- put_user(*tmp++, buf++);
- len--;
- }
- read_space(error);
-done:
- return error;
-}
-
-int compute_name(struct dentry * entry, char * buf)
-{
- int len;
-
- if(IS_ROOT(entry)) {
- *buf = '/';
- return 1;
- }
- len = compute_name(entry->d_parent, buf);
- if(len > 1) {
- buf[len++] = '/';
- }
- memcpy(buf+len, entry->d_name, entry->d_len);
- return len + entry->d_len;
-}
-
-int _omirr_print(struct dentry * ent1, struct dentry * ent2,
- struct qstr * suffix, const char * fmt,
- va_list args1, va_list args2)
-{
- int count = strlen(fmt) + 10; /* estimate */
- const char * tmp = fmt;
- char lenbuf[8];
- int res;
-
- if(!buffer)
- init_buffer(NULL);
- while(*tmp) {
- while(*tmp && *tmp++ != '%') ;
- if(*tmp) {
- if(*tmp == 's') {
- char * str = va_arg(args1, char*);
- count += strlen(str);
- } else {
- (void)va_arg(args1, int);
- count += 8; /* estimate */
- }
- }
- }
- if(ent1) {
- struct dentry * dent = ent1;
- while(dent && !IS_ROOT(dent)) {
- count += dent->d_len + 1;
- dent = dent->d_parent;
- }
- count++;
- if(ent2) {
- dent = ent2;
- while(dent && !IS_ROOT(dent)) {
- count += dent->d_len + 1;
- dent = dent->d_parent;
- }
- count++;
- }
- if(suffix)
- count += suffix->len + 1;
- }
-
- if((nr_omirr_open | cleared_flag) && reserve_write_space(count)) {
- cleared_flag = 0;
- res = vsprintf(buffer+write_pos+4, fmt, args2) + 4;
- if(res > count)
- printk("omirr: format estimate was wrong\n");
- if(ent1) {
- res += compute_name(ent1, buffer+write_pos+res);
- if(ent2) {
- buffer[write_pos+res++] = '\0';
- res += compute_name(ent2, buffer+write_pos+res);
- }
- if(suffix) {
- buffer[write_pos+res++] = '/';
- memcpy(buffer+write_pos+res,
- suffix->name, suffix->len);
- res += suffix->len;
- }
- buffer[write_pos+res++] = '\0';
- buffer[write_pos+res++] = '\n';
- }
- sprintf(lenbuf, "%04d", res);
- memcpy(buffer+write_pos, lenbuf, 4);
- } else {
- if(!cleared_flag) {
- cleared_flag = 1;
- init_buffer("0007 Z\n");
- }
- res = 0;
- }
- write_space(res);
- return res;
-}
-
-int omirr_print(struct dentry * ent1, struct dentry * ent2,
- struct qstr * suffix, const char * fmt, ...)
-{
- va_list args1, args2;
- int res;
-
- /* I don't know whether I could make a simple copy of the va_list,
- * so for the safe way...
- */
- va_start(args1, fmt);
- va_start(args2, fmt);
- res = _omirr_print(ent1, ent2, suffix, fmt, args1, args2);
- va_end(args2);
- va_end(args1);
- return res;
-}
-
-int omirr_printall(struct inode * inode, const char * fmt, ...)
-{
- int res = 0;
- struct dentry * tmp = inode->i_dentry;
-
- if(tmp) do {
- va_list args1, args2;
- va_start(args1, fmt);
- va_start(args2, fmt);
- res += _omirr_print(tmp, NULL, NULL, fmt, args1, args2);
- va_end(args2);
- va_end(args1);
- tmp = tmp->d_next;
- } while(tmp != inode->i_dentry);
- return res;
-}
-
-static struct file_operations omirr_operations = {
- NULL, /* omirr_lseek */
- omirr_read,
- NULL, /* omirr_write */
- NULL, /* omirr_readdir */
- NULL, /* omirr_select */
- NULL, /* omirr_ioctl */
- NULL, /* mmap */
- omirr_open,
- NULL, /* flush */
- omirr_release,
- NULL, /* fsync */
- NULL, /* fasync */
-};
-
-struct inode_operations proc_omirr_inode_operations = {
- &omirr_operations,
-};
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 00b09e6a7..3ad4bfabf 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -29,6 +29,7 @@
#include <linux/smp.h>
#include <linux/signal.h>
#include <linux/module.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -593,9 +594,8 @@ static ssize_t write_profile(struct file * file, const char * buf,
}
static struct file_operations proc_profile_operations = {
- NULL, /* lseek */
- read_profile,
- write_profile,
+ read: read_profile,
+ write: write_profile,
};
static struct inode_operations proc_profile_inode_operations = {
@@ -618,7 +618,7 @@ static struct proc_dir_entry proc_root_profile = {
0, &proc_profile_inode_operations
};
-void proc_misc_init(void)
+void __init proc_misc_init(void)
{
static struct {
char *name;
diff --git a/fs/proc/procfs_syms.c b/fs/proc/procfs_syms.c
index 45d80dd5f..cc1ae7d96 100644
--- a/fs/proc/procfs_syms.c
+++ b/fs/proc/procfs_syms.c
@@ -2,6 +2,7 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
+#include <linux/init.h>
extern struct proc_dir_entry *proc_sys_root;
@@ -26,7 +27,7 @@ static struct file_system_type proc_fs_type = {
NULL
};
-int init_proc_fs(void)
+int __init init_proc_fs(void)
{
return register_filesystem(&proc_fs_type) == 0;
}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 75780167a..8bacabed2 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -143,10 +143,7 @@ static int proc_root_readdir(struct file * filp,
* directory handling functions for that..
*/
static struct file_operations proc_root_operations = {
- NULL, /* lseek - default */
- NULL, /* read - bad */
- NULL, /* write - bad */
- proc_root_readdir, /* readdir */
+ readdir: proc_root_readdir,
};
/*
diff --git a/fs/qnx4/Makefile b/fs/qnx4/Makefile
index 1988bb8ff..943eb1223 100644
--- a/fs/qnx4/Makefile
+++ b/fs/qnx4/Makefile
@@ -8,8 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := qnx4.o
-O_OBJS := inode.o dir.o namei.o file.o bitmap.o symlinks.o truncate.o \
-fsync.o
+O_OBJS := inode.o dir.o namei.o file.o bitmap.o truncate.o fsync.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/fs/qnx4/file.c b/fs/qnx4/file.c
index 80ab1f590..6eb3ca0a5 100644
--- a/fs/qnx4/file.c
+++ b/fs/qnx4/file.c
@@ -17,130 +17,6 @@
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/qnx4_fs.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/malloc.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/locks.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-
-
-#ifdef CONFIG_QNX4FS_RW
-static ssize_t qnx4_file_write(struct file *filp, const char *buf,
- size_t count, loff_t * ppos)
-{
- struct dentry *dentry = filp->f_dentry;
- struct inode *inode = dentry->d_inode;
- struct qnx4_inode_info *qnx4_ino;
- struct buffer_head *bh;
- ssize_t result = -EBUSY, c;
- off_t pos;
- unsigned long start, block, extent_end;
- char *p;
-
- QNX4DEBUG(("qnx4: file_write(%s/%s (%d), %lu@%lu)\n",
- dentry->d_parent->d_name.name, dentry->d_name.name,
- inode->i_count, (unsigned long) count, (unsigned long) *ppos));
- if (inode == NULL) {
- printk("qnx4: NULL inode for file_write\n");
- return -EINVAL;
- }
- qnx4_ino = &inode->u.qnx4_i;
- if (S_ISREG(inode->i_mode) == 0) {
- printk("qnx4: write to non-file, mode %07o\n", inode->i_mode);
- return -EINVAL;
- }
- if (count == 0) {
- goto out;
- }
- if (filp->f_flags & O_APPEND) {
- pos = inode->i_size;
- } else {
- pos = *ppos;
- }
- start = qnx4_ino->i_first_xtnt.xtnt_blk + ((pos >> 9) * 0) - 1;
- result = 0;
- extent_end = start + qnx4_ino->i_first_xtnt.xtnt_size - 1;
- QNX4DEBUG(("qnx4: extent length : [%lu] bytes\n",
- qnx4_ino->i_first_xtnt.xtnt_size));
- while (result < count) {
- block = start + pos / QNX4_BLOCK_SIZE;
- if (block > extent_end) {
- if (qnx4_is_free(inode->i_sb, block) <= 0) {
- printk("qnx4: next inode is busy -> write aborted.\n");
- result = -ENOSPC;
- break;
- }
- }
- if ((bh = bread(inode->i_dev, block,
- QNX4_BLOCK_SIZE)) == NULL) {
- printk("qnx4: I/O error on write.\n");
- result = -EIO;
- goto out;
- }
- if (bh == NULL) {
- if (result != 0) {
- result = -ENOSPC;
- }
- break;
- }
- if (block > extent_end) {
- qnx4_set_bitmap(inode->i_sb, block, 1);
- extent_end++;
- qnx4_ino->i_first_xtnt.xtnt_size = extent_end - start + 1;
- }
- c = QNX4_BLOCK_SIZE - (pos % QNX4_BLOCK_SIZE);
- if (c > count - result) {
- c = count - result;
- }
- if (c != QNX4_BLOCK_SIZE && buffer_uptodate(bh) == 0) {
- ll_rw_block(WRITE, 1, &bh);
- wait_on_buffer(bh);
- if (buffer_uptodate(bh) == 0) {
- brelse(bh);
- if (result != 0) {
- result = -EIO;
- }
- break;
- }
- }
- p = bh->b_data + (pos % QNX4_BLOCK_SIZE);
- c -= copy_from_user(p, buf, c);
- if (c == 0) {
- brelse(bh);
- if (result == 0) {
- result = -EFAULT;
- }
- break;
- }
-// update_vm_cache(inode, pos, p, c);
- mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh, 0);
- brelse(bh);
- pos += c;
- buf += c;
- result += c;
- }
- if (pos > inode->i_size) {
- inode->i_size = pos;
- }
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- *ppos = pos;
- mark_inode_dirty(inode);
-
- out:
- return result;
-}
-#endif
/*
* We have mostly NULL's here: the current defaults are ok for
@@ -150,7 +26,7 @@ static struct file_operations qnx4_file_operations =
{
read: generic_file_read,
#ifdef CONFIG_QNX4FS_RW
- write: qnx4_file_write,
+ write: generic_file_write,
#endif
mmap: generic_file_mmap,
#ifdef CONFIG_QNX4FS_RW
@@ -161,10 +37,7 @@ static struct file_operations qnx4_file_operations =
struct inode_operations qnx4_file_inode_operations =
{
default_file_ops: &qnx4_file_operations,
- get_block: qnx4_get_block,
- readpage: block_read_full_page,
#ifdef CONFIG_QNX4FS_RW
- writepage: block_write_full_page,
truncate: qnx4_truncate,
#endif
};
diff --git a/fs/qnx4/fsync.c b/fs/qnx4/fsync.c
index 4cea74fe5..e90291f03 100644
--- a/fs/qnx4/fsync.c
+++ b/fs/qnx4/fsync.c
@@ -16,6 +16,7 @@
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/locks.h>
+#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <linux/qnx4_fs.h>
@@ -156,10 +157,12 @@ int qnx4_sync_file(struct file *file, struct dentry *dentry)
S_ISLNK(inode->i_mode)))
return -EINVAL;
+ lock_kernel();
for (wait = 0; wait <= 1; wait++) {
err |= sync_direct(inode, wait);
}
err |= qnx4_sync_inode(inode);
+ unlock_kernel();
return (err < 0) ? -EIO : 0;
}
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 5b70d5211..abb6d8260 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -423,6 +423,31 @@ static void qnx4_put_super(struct super_block *sb)
return;
}
+static int qnx4_writepage(struct dentry *dentry, struct page *page)
+{
+ return block_write_full_page(page,qnx4_get_block);
+}
+static int qnx4_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,qnx4_get_block);
+}
+static int qnx4_prepare_write(struct page *page, unsigned from, unsigned to)
+{
+ return cont_prepare_write(page,from,to,qnx4_get_block,
+ &((struct inode*)page->mapping->host)->u.qnx4_i.mmu_private);
+}
+static int qnx4_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,qnx4_get_block);
+}
+struct address_space_operations qnx4_aops = {
+ readpage: qnx4_readpage,
+ writepage: qnx4_writepage,
+ prepare_write: qnx4_prepare_write,
+ commit_write: generic_commit_write,
+ bmap: qnx4_bmap
+};
+
static void qnx4_read_inode(struct inode *inode)
{
struct buffer_head *bh;
@@ -461,14 +486,17 @@ static void qnx4_read_inode(struct inode *inode)
inode->i_blksize = QNX4_DIR_ENTRY_SIZE;
memcpy(&inode->u.qnx4_i, (struct qnx4_inode_info *) raw_inode, QNX4_DIR_ENTRY_SIZE);
- inode->i_op = &qnx4_file_inode_operations;
- if (S_ISREG(inode->i_mode))
+ if (S_ISREG(inode->i_mode)) {
inode->i_op = &qnx4_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
+ inode->i_mapping->a_ops = &qnx4_aops;
+ inode->u.qnx4_i.mmu_private = inode->i_size;
+ } else if (S_ISDIR(inode->i_mode))
inode->i_op = &qnx4_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &qnx4_symlink_inode_operations;
- else
+ else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_mapping->a_ops = &qnx4_aops;
+ inode->u.qnx4_i.mmu_private = inode->i_size;
+ } else
/* HUH??? Where is device number? Oh, well... */
init_special_inode(inode, inode->i_mode, 0);
diff --git a/fs/qnx4/symlinks.c b/fs/qnx4/symlinks.c
deleted file mode 100644
index 4eaf27034..000000000
--- a/fs/qnx4/symlinks.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * QNX4 file system, Linux implementation.
- *
- * Version : 0.2.1
- *
- * Using parts of the xiafs filesystem.
- *
- * History :
- *
- * 28-05-1998 by Richard Frowijn : first release.
- * 21-06-1998 by Frank Denis : ugly changes to make it compile on Linux 2.1.99+
- */
-
-#include <linux/fs.h>
-#include <linux/qnx4_fs.h>
-
-/*
- * symlinks can't do much...
- */
-struct inode_operations qnx4_symlink_inode_operations =
-{
- readlink: page_readlink,
- follow_link: page_follow_link,
- get_block: qnx4_get_block,
- readpage: block_read_full_page,
-};
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index 692754912..ab5972591 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -446,47 +446,21 @@ romfs_readpage(struct dentry * dentry, struct page * page)
/* Mapping from our types to the kernel */
+static struct address_space_operations romfs_aops = {
+ readpage: romfs_readpage
+};
+
static struct file_operations romfs_file_operations = {
- NULL, /* lseek - default */
- generic_file_read, /* read */
- NULL, /* write - bad */
- NULL, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl */
- generic_file_mmap, /* mmap */
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
+ read: generic_file_read,
+ mmap: generic_file_mmap,
};
static struct inode_operations romfs_file_inode_operations = {
&romfs_file_operations,
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block -- not really */
- romfs_readpage, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
static struct file_operations romfs_dir_operations = {
- NULL, /* lseek - default */
- NULL, /* read */
- NULL, /* write - bad */
- romfs_readdir, /* readdir */
+ readdir: romfs_readdir,
};
/* Merged dir/symlink op table. readdir/lookup/readlink/follow_link
@@ -497,27 +471,6 @@ static struct inode_operations romfs_dir_inode_operations = {
&romfs_dir_operations,
NULL, /* create */
romfs_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
-};
-
-static struct inode_operations romfs_link_inode_operations = {
- readlink: page_readlink,
- follow_link: page_follow_link,
- readpage: romfs_readpage
};
static mode_t romfs_modemap[] =
@@ -531,7 +484,7 @@ static struct inode_operations *romfs_inoops[] =
NULL, /* hardlink, handled elsewhere */
&romfs_dir_inode_operations,
&romfs_file_inode_operations,
- &romfs_link_inode_operations,
+ &page_symlink_inode_operations,
NULL, /* device/fifo/socket nodes, */
NULL, /* set by init_special_inode */
NULL,
@@ -587,6 +540,8 @@ romfs_read_inode(struct inode *i)
i->i_mode = ino;
if (S_ISDIR(ino))
i->i_size = i->u.romfs_i.i_metasize;
+ else
+ i->i_data.a_ops = &romfs_aops;
} else {
/* depending on MBZ for sock/fifos */
nextfh = ntohl(ri.spec);
diff --git a/fs/select.c b/fs/select.c
index 7df7e0c9b..33e54a9fa 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -43,6 +43,39 @@
* Linus noticed. -- jrs
*/
+static poll_table* alloc_wait(int nfds)
+{
+ poll_table* out;
+ poll_table* walk;
+
+ out = (poll_table *) __get_free_page(GFP_KERNEL);
+ if(out==NULL)
+ return NULL;
+ out->nr = 0;
+ out->entry = (struct poll_table_entry *)(out + 1);
+ out->next = NULL;
+ nfds -=__MAX_POLL_TABLE_ENTRIES;
+ walk = out;
+ while(nfds > 0) {
+ poll_table *tmp = (poll_table *) __get_free_page(GFP_KERNEL);
+ if (!tmp) {
+ while(out != NULL) {
+ tmp = out->next;
+ free_page((unsigned long)out);
+ out = tmp;
+ }
+ return NULL;
+ }
+ tmp->nr = 0;
+ tmp->entry = (struct poll_table_entry *)(tmp + 1);
+ tmp->next = NULL;
+ walk->next = tmp;
+ walk = tmp;
+ nfds -=__MAX_POLL_TABLE_ENTRIES;
+ }
+ return out;
+}
+
static void free_wait(poll_table * p)
{
struct poll_table_entry * entry;
@@ -67,7 +100,6 @@ void __pollwait(struct file * filp, wait_queue_head_t * wait_address, poll_table
for (;;) {
if (p->nr < __MAX_POLL_TABLE_ENTRIES) {
struct poll_table_entry * entry;
-ok_table:
entry = p->entry + p->nr;
get_file(filp);
entry->filp = filp;
@@ -77,17 +109,6 @@ ok_table:
p->nr++;
return;
}
- if (p->next == NULL) {
- poll_table *tmp = (poll_table *) __get_free_page(GFP_KERNEL);
- if (!tmp)
- return;
- tmp->nr = 0;
- tmp->entry = (struct poll_table_entry *)(tmp + 1);
- tmp->next = NULL;
- p->next = tmp;
- p = tmp;
- goto ok_table;
- }
p = p->next;
}
}
@@ -152,33 +173,28 @@ get_max:
int do_select(int n, fd_set_bits *fds, long *timeout)
{
- poll_table *wait_table, *wait;
+ poll_table *wait, *orig_wait;
int retval, i, off;
long __timeout = *timeout;
- wait = wait_table = NULL;
- if (__timeout) {
- wait_table = (poll_table *) __get_free_page(GFP_KERNEL);
- if (!wait_table)
- return -ENOMEM;
-
- wait_table->nr = 0;
- wait_table->entry = (struct poll_table_entry *)(wait_table + 1);
- wait_table->next = NULL;
- wait = wait_table;
- }
+ orig_wait = wait = NULL;
- read_lock(&current->files->file_lock);
+ read_lock(&current->files->file_lock);
retval = max_select_fd(n, fds);
read_unlock(&current->files->file_lock);
- lock_kernel();
if (retval < 0)
- goto out;
+ return retval;
n = retval;
+ if (__timeout) {
+ orig_wait = wait = alloc_wait(n);
+ if (!wait)
+ return -ENOMEM;
+ }
retval = 0;
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
+ lock_kernel();
for (i = 0 ; i < n; i++) {
unsigned long bit = BIT(i);
unsigned long mask;
@@ -211,6 +227,7 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
wait = NULL;
}
}
+ unlock_kernel();
wait = NULL;
if (retval || !__timeout || signal_pending(current))
break;
@@ -218,15 +235,12 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
}
current->state = TASK_RUNNING;
-out:
- if (*timeout)
- free_wait(wait_table);
+ free_wait(orig_wait);
/*
* Up-to-date the caller timeout.
*/
*timeout = __timeout;
- unlock_kernel();
return retval;
}
@@ -334,29 +348,36 @@ out_nofds:
#define POLLFD_PER_PAGE ((PAGE_SIZE) / sizeof(struct pollfd))
-static void do_pollfd(struct pollfd * fdp, poll_table * wait, int *count)
+static void do_pollfd(unsigned int num, struct pollfd * fdpage,
+ poll_table ** pwait, 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)++;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ int fd;
+ unsigned int mask;
+ struct pollfd *fdp;
+
+ mask = 0;
+ fdp = fdpage+i;
+ 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, *pwait);
+ mask &= fdp->events | POLLERR | POLLHUP;
+ fput(file);
+ }
+ if (mask) {
+ *pwait = NULL;
+ (*count)++;
+ }
}
+ fdp->revents = mask;
}
- fdp->revents = mask;
}
static int do_poll(unsigned int nfds, unsigned int nchunks, unsigned int nleft,
@@ -365,16 +386,13 @@ static int do_poll(unsigned int nfds, unsigned int nchunks, unsigned int nleft,
int count = 0;
for (;;) {
- unsigned int i, j;
+ unsigned int i;
set_current_state(TASK_INTERRUPTIBLE);
for (i=0; i < nchunks; i++)
- for (j = 0; j < POLLFD_PER_PAGE; j++)
- do_pollfd(fds[i] + j, wait, &count);
+ do_pollfd(POLLFD_PER_PAGE, fds[i], &wait, &count);
if (nleft)
- for (j = 0; j < nleft; j++)
- do_pollfd(fds[nchunks] + j, wait, &count);
-
+ do_pollfd(nleft, fds[nchunks], &wait, &count);
wait = NULL;
if (count || !timeout || signal_pending(current))
break;
@@ -388,7 +406,7 @@ asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
{
int i, j, fdcount, err;
struct pollfd **fds;
- poll_table *wait_table = NULL, *wait = NULL;
+ poll_table *wait = NULL;
int nchunks, nleft;
/* Do a sanity check on nfds ... */
@@ -403,16 +421,12 @@ asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
timeout = MAX_SCHEDULE_TIMEOUT;
}
- err = -ENOMEM;
if (timeout) {
- wait_table = (poll_table *) __get_free_page(GFP_KERNEL);
- if (!wait_table)
- goto out;
- wait_table->nr = 0;
- wait_table->entry = (struct poll_table_entry *)(wait_table + 1);
- wait_table->next = NULL;
- wait = wait_table;
+ wait = alloc_wait(nfds);
+ if (!wait)
+ return -ENOMEM;
}
+ err = -ENOMEM;
fds = NULL;
if (nfds != 0) {
@@ -473,7 +487,6 @@ out_fds:
if (nfds != 0)
kfree(fds);
out:
- if (wait)
- free_wait(wait_table);
+ free_wait(wait);
return err;
}
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 37bf168f6..68351b4b4 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -32,17 +32,10 @@ static int smb_rename(struct inode *, struct dentry *,
static struct file_operations smb_dir_operations =
{
- NULL, /* lseek - default */
- smb_dir_read, /* read - bad */
- NULL, /* write - bad */
- smb_readdir, /* readdir */
- NULL, /* poll - default */
- smb_ioctl, /* ioctl */
- NULL, /* mmap */
- smb_dir_open, /* open(struct inode *, struct file *) */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* fsync */
+ read: smb_dir_read,
+ readdir: smb_readdir,
+ ioctl: smb_ioctl,
+ open: smb_dir_open,
};
struct inode_operations smb_dir_inode_operations =
@@ -59,9 +52,6 @@ struct inode_operations smb_dir_inode_operations =
smb_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
NULL, /* truncate */
NULL, /* permission */
smb_revalidate_inode, /* revalidate */
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index f5aff8730..a62de1256 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -260,20 +260,31 @@ out:
* If the writer ends up delaying the write, the writer needs to
* increment the page use counts until he is done with the page.
*/
-static int smb_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+static int smb_prepare_write(struct page *page, unsigned offset, unsigned to)
+{
+ kmap(page);
+ return 0;
+}
+
+static int smb_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
int status;
- bytes -= copy_from_user((u8*)page_address(page) + offset, buf, bytes);
status = -EFAULT;
- if (bytes) {
- lock_kernel();
- status = smb_updatepage(file, page, offset, bytes);
- unlock_kernel();
- }
+ lock_kernel();
+ status = smb_updatepage(file, page, offset, to-offset);
+ unlock_kernel();
+ kunmap(page);
return status;
}
+struct address_space_operations smb_file_aops = {
+ readpage: smb_readpage,
+ writepage: smb_writepage,
+ prepare_write: smb_prepare_write,
+ commit_write: smb_commit_write
+};
+
/*
* Write to a file (through the page cache).
*/
@@ -305,7 +316,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, result);
if (count > 0)
{
- result = generic_file_write(file, buf, count, ppos, smb_write_one_page);
+ result = generic_file_write(file, buf, count, ppos);
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_file_write: pos=%ld, size=%ld, mtime=%ld, atime=%ld\n",
(long) file->f_pos, dentry->d_inode->i_size, dentry->d_inode->i_mtime,
@@ -367,19 +378,13 @@ printk("smb_file_permission: mode=%x, mask=%x\n", mode, mask);
static struct file_operations smb_file_operations =
{
- NULL, /* lseek - default */
- smb_file_read, /* read */
- smb_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- smb_ioctl, /* ioctl */
- smb_file_mmap, /* mmap(struct file*, struct vm_area_struct*) */
- smb_file_open, /* open(struct inode*, struct file*) */
- NULL, /* flush */
- smb_file_release, /* release(struct inode*, struct file*) */
- smb_fsync, /* fsync(struct file*, struct dentry*) */
- NULL, /* fasync(struct file*, int) */
- NULL /* lock(struct file*, int, struct file_lock*) */
+ read: smb_file_read,
+ write: smb_file_write,
+ ioctl: smb_ioctl,
+ mmap: smb_file_mmap,
+ open: smb_file_open,
+ release: smb_file_release,
+ fsync: smb_fsync,
};
struct inode_operations smb_file_inode_operations =
@@ -396,9 +401,6 @@ struct inode_operations smb_file_inode_operations =
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* get_block */
- smb_readpage, /* readpage */
- smb_writepage, /* writepage */
NULL, /* truncate */
smb_file_permission, /* permission */
smb_revalidate_inode, /* revalidate */
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index b4dcc2a32..c071263ff 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -82,9 +82,10 @@ smb_iget(struct super_block *sb, struct smb_fattr *fattr)
result->i_ino = fattr->f_ino;
memset(&(result->u.smbfs_i), 0, sizeof(result->u.smbfs_i));
smb_set_inode_attr(result, fattr);
- if (S_ISREG(result->i_mode))
+ if (S_ISREG(result->i_mode)) {
result->i_op = &smb_file_inode_operations;
- else if (S_ISDIR(result->i_mode))
+ result->i_data.a_ops = &smb_file_aops;
+ } else if (S_ISDIR(result->i_mode))
result->i_op = &smb_dir_inode_operations;
else
result->i_op = NULL;
diff --git a/fs/stat.c b/fs/stat.c
index 892d3417d..af90ac70b 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -284,7 +284,7 @@ asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz)
/* ---------- LFS-64 ----------- */
-#if !defined(__alpha__) && !defined(__mips64)
+#if !defined(__alpha__) && !defined (__ia64__) && !defined(__mips64)
static long cp_new_stat64(struct inode * inode, struct stat64 * statbuf)
{
diff --git a/fs/super.c b/fs/super.c
index 71b38fd46..4e7146fcf 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1378,7 +1378,10 @@ int __init change_root(kdev_t new_root_dev,const char *put_old)
bdev = do_umount(old_root_dev,1, 0);
if (!IS_ERR(bdev)) {
printk("okay\n");
- invalidate_buffers(old_root_dev);
+ /* special: the old device driver is going to be
+ a ramdisk and the point of this call is to free its
+ protected memory (even if dirty). */
+ destroy_buffers(old_root_dev);
if (bdev) {
blkdev_put(bdev, BDEV_FS);
bdput(bdev);
diff --git a/fs/sysv/Makefile b/fs/sysv/Makefile
index 6c31360fd..394af0b4d 100644
--- a/fs/sysv/Makefile
+++ b/fs/sysv/Makefile
@@ -8,8 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile.
O_TARGET := sysv.o
-O_OBJS := ialloc.o balloc.o inode.o file.o dir.o symlink.o namei.o \
- fsync.o truncate.o
+O_OBJS := ialloc.o balloc.o inode.o file.o dir.o namei.o fsync.o truncate.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index f17fb8b63..f21a47578 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -30,17 +30,9 @@ static ssize_t sysv_dir_read(struct file * filp, char * buf,
static int sysv_readdir(struct file *, void *, filldir_t);
static struct file_operations sysv_dir_operations = {
- NULL, /* lseek - default */
- sysv_dir_read, /* read */
- NULL, /* write - bad */
- sysv_readdir, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- file_fsync /* default fsync */
+ read: sysv_dir_read,
+ readdir: sysv_readdir,
+ fsync: file_fsync,
};
/*
@@ -57,14 +49,6 @@ struct inode_operations sysv_dir_inode_operations = {
sysv_rmdir, /* rmdir */
sysv_mknod, /* mknod */
sysv_rename, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
diff --git a/fs/sysv/file.c b/fs/sysv/file.c
index 2a0d03850..b60a1d02e 100644
--- a/fs/sysv/file.c
+++ b/fs/sysv/file.c
@@ -23,59 +23,18 @@
#include <linux/locks.h>
#include <linux/pagemap.h>
-#include <asm/uaccess.h>
-
-#define NBUF 32
-
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-
-/*
- * Write to a file (through the page cache).
- */
-static ssize_t
-sysv_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
-{
- return generic_file_write(file, buf, count,
- ppos, block_write_partial_page);
-}
-
/*
* We have mostly NULLs here: the current defaults are OK for
* the coh filesystem.
*/
static struct file_operations sysv_file_operations = {
- NULL, /* lseek - default */
- generic_file_read, /* read */
- sysv_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- generic_file_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- NULL, /* release */
- sysv_sync_file, /* fsync */
- NULL, /* fasync */
+ read: generic_file_read,
+ write: generic_file_write,
+ mmap: generic_file_mmap,
+ fsync: sysv_sync_file,
};
struct inode_operations sysv_file_inode_operations = {
- &sysv_file_operations, /* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- sysv_get_block, /* get_block */
- block_read_full_page, /* readpage */
- block_write_full_page, /* writepage */
- sysv_truncate, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
+ &sysv_file_operations,
+ truncate: sysv_truncate,
};
diff --git a/fs/sysv/fsync.c b/fs/sysv/fsync.c
index b0e1138c7..3c9871be6 100644
--- a/fs/sysv/fsync.c
+++ b/fs/sysv/fsync.c
@@ -16,9 +16,9 @@
#include <linux/errno.h>
#include <linux/stat.h>
-
#include <linux/fs.h>
#include <linux/sysv_fs.h>
+#include <linux/smp_lock.h>
/* return values: 0 means OK/done, 1 means redo, -1 means I/O error. */
@@ -187,6 +187,7 @@ int sysv_sync_file(struct file * file, struct dentry *dentry)
S_ISLNK(inode->i_mode)))
return -EINVAL;
+ lock_kernel();
for (wait=0; wait<=1; wait++) {
err |= sync_direct(inode, wait);
err |= sync_indirect(inode, inode->u.sysv_i.i_data+10, 0, wait);
@@ -194,5 +195,6 @@ int sysv_sync_file(struct file * file, struct dentry *dentry)
err |= sync_tindirect(inode, inode->u.sysv_i.i_data+12, 0, wait);
}
err |= sysv_sync_inode (inode);
+ unlock_kernel();
return (err < 0) ? -EIO : 0;
}
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index cfe016728..6580b6125 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -832,7 +832,7 @@ out:
return result;
}
-int sysv_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create)
+static int sysv_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create)
{
struct super_block *sb;
int ret, err, new;
@@ -961,6 +961,30 @@ struct buffer_head *sysv_file_bread(struct inode *inode, int block, int create)
return NULL;
}
+static int sysv_writepage(struct dentry *dentry, struct page *page)
+{
+ return block_write_full_page(page,sysv_get_block);
+}
+static int sysv_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,sysv_get_block);
+}
+static int sysv_prepare_write(struct page *page, unsigned from, unsigned to)
+{
+ return block_prepare_write(page,from,to,sysv_get_block);
+}
+static int sysv_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,sysv_get_block);
+}
+struct address_space_operations sysv_aops = {
+ readpage: sysv_readpage,
+ writepage: sysv_writepage,
+ prepare_write: sysv_prepare_write,
+ commit_write: generic_commit_write,
+ bmap: sysv_bmap
+};
+
#ifdef __BIG_ENDIAN
static inline unsigned long read3byte (unsigned char * p)
@@ -1059,13 +1083,15 @@ static void sysv_read_inode(struct inode *inode)
for (block = 0; block < 10+1+1+1; block++)
inode->u.sysv_i.i_data[block] =
read3byte(&raw_inode->i_a.i_addb[3*block]);
- if (S_ISREG(inode->i_mode))
+ if (S_ISREG(inode->i_mode)) {
inode->i_op = &sysv_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
+ inode->i_mapping->a_ops = &sysv_aops;
+ } else if (S_ISDIR(inode->i_mode))
inode->i_op = &sysv_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &sysv_symlink_inode_operations;
- else
+ else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_mapping->a_ops = &sysv_aops;
+ } else
init_special_inode(inode, inode->i_mode,raw_inode->i_a.i_rdev);
brelse(bh);
}
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index 844912898..9661af99c 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -204,6 +204,7 @@ int sysv_create(struct inode * dir, struct dentry * dentry, int mode)
if (!inode)
return -ENOSPC;
inode->i_op = &sysv_file_inode_operations;
+ inode->i_mapping->a_ops = &sysv_aops;
inode->i_mode = mode;
mark_inode_dirty(inode);
error = sysv_add_entry(dir, dentry->d_name.name,
@@ -455,7 +456,8 @@ int sysv_symlink(struct inode * dir, struct dentry * dentry,
goto out;
inode->i_mode = S_IFLNK | 0777;
- inode->i_op = &sysv_symlink_inode_operations;
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_mapping->a_ops = &sysv_aops;
err = block_symlink(inode, symname, l);
if (err)
goto out_no_entry;
diff --git a/fs/sysv/symlink.c b/fs/sysv/symlink.c
deleted file mode 100644
index 3f77f831e..000000000
--- a/fs/sysv/symlink.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * linux/fs/sysv/symlink.c
- *
- * minix/symlink.c
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * coh/symlink.c
- * Copyright (C) 1993 Pascal Haible, Bruno Haible
- *
- * sysv/symlink.c
- * Copyright (C) 1993 Bruno Haible
- *
- * SystemV/Coherent symlink handling code
- */
-
-#include <linux/sysv_fs.h>
-
-/*
- * symlinks can't do much...
- */
-struct inode_operations sysv_symlink_inode_operations = {
- readlink: page_readlink,
- follow_link: page_follow_link,
- get_block: sysv_get_block,
- readpage: block_read_full_page
-};
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index 916683186..963d20344 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -50,19 +50,9 @@ static int do_udf_readdir(struct inode *, struct file *, filldir_t, void *);
/* readdir and lookup functions */
static struct file_operations udf_dir_operations = {
- NULL, /* lllseek */
- NULL, /* read */
- NULL, /* write */
- udf_readdir, /* readdir */
- NULL, /* poll */
- udf_ioctl, /* ioctl */
- NULL, /* mmap */
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- udf_sync_file, /* fsync */
- NULL, /* fasync */
- NULL /* lock */
+ readdir: udf_readdir,
+ ioctl: udf_ioctl,
+ fsync: udf_sync_file,
};
struct inode_operations udf_dir_inode_operations = {
@@ -90,14 +80,6 @@ struct inode_operations udf_dir_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
#endif
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
/*
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 8ea44d2a8..5cf51cd0e 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -72,110 +72,119 @@ static loff_t udf_file_llseek(struct file * file, loff_t offset, int origin)
return offset;
}
-static inline void remove_suid(struct inode * inode)
+static int udf_adinicb_readpage(struct dentry *dentry, struct page * page)
{
- unsigned int mode;
+ struct inode *inode = dentry->d_inode;
- /* set S_IGID if S_IXGRP is set, and always set S_ISUID */
- mode = (inode->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID;
-
- /* was any of the uid bits set? */
- mode &= inode->i_mode;
- if (mode && !capable(CAP_FSETID))
- {
- inode->i_mode &= ~mode;
- mark_inode_dirty(inode);
- }
-}
-
-static ssize_t udf_file_write(struct file * file, const char * buf,
- size_t count, loff_t *ppos)
-{
- ssize_t retval;
- struct inode *inode = file->f_dentry->d_inode;
+ struct buffer_head *bh;
+ unsigned long kaddr = 0;
- retval = generic_file_write(file, buf, count, ppos, block_write_partial_page);
+ if (!PageLocked(page))
+ PAGE_BUG(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);
- }
- return retval;
+ kaddr = kmap(page);
+ memset((char *)kaddr, 0, PAGE_CACHE_SIZE);
+ bh = getblk (inode->i_dev, inode->i_ino, 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_write_partial_page_adinicb(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+static int udf_adinicb_writepage(struct dentry *dentry, struct page *page)
{
- struct inode *inode = file->f_dentry->d_inode;
- int err = 0, block;
+ struct inode *inode = dentry->d_inode;
+
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);
+ bh = getblk (inode->i_dev, inode->i_ino, 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_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;
+}
+
+static int udf_adinicb_prepare_write(struct page *page, unsigned offset, unsigned to)
+{
+ kmap(page);
+ return 0;
+}
+
+static int udf_adinicb_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct buffer_head *bh;
+ char *kaddr = (char*)page_address(page);
+ bh = bread (inode->i_dev, inode->i_ino, inode->i_sb->s_blocksize);
+ if (!buffer_uptodate(bh)) {
+ ll_rw_block (READ, 1, &bh);
+ wait_on_buffer(bh);
+ }
memcpy(bh->b_data + udf_file_entry_alloc_offset(inode) + offset,
- (char *)kaddr + offset, bytes);
+ kaddr + offset, to-offset);
mark_buffer_dirty(bh, 0);
brelse(bh);
kunmap(page);
SetPageUptodate(page);
- return bytes;
+ return 0;
}
-static ssize_t udf_file_write_adinicb(struct file * file, const char * buf,
+struct address_space_operations udf_adinicb_aops = {
+ readpage: udf_adinicb_readpage,
+ writepage: udf_adinicb_writepage,
+ prepare_write: udf_adinicb_prepare_write,
+ commit_write: udf_adinicb_commit_write
+};
+
+static ssize_t udf_file_write(struct file * file, const char * buf,
size_t count, loff_t *ppos)
{
ssize_t retval;
struct inode *inode = file->f_dentry->d_inode;
int err, pos;
- if (file->f_flags & O_APPEND)
- pos = inode->i_size;
- else
- pos = *ppos;
-
- if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
- pos + count))
- {
- 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);
- }
- else
- {
- if (pos + count > inode->i_size)
- UDF_I_LENALLOC(inode) = pos + count;
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB) {
+ if (file->f_flags & O_APPEND)
+ pos = inode->i_size;
else
- UDF_I_LENALLOC(inode) = inode->i_size;
+ pos = *ppos;
+
+ if (inode->i_sb->s_blocksize <
+ (udf_file_entry_alloc_offset(inode) + pos + count)) {
+ 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 {
+ if (pos + count > inode->i_size)
+ UDF_I_LENALLOC(inode) = pos + count;
+ else
+ UDF_I_LENALLOC(inode) = inode->i_size;
+ }
}
- retval = generic_file_write(file, buf, count, ppos, udf_write_partial_page_adinicb);
-
- if (retval > 0)
- {
- remove_suid(inode);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ retval = generic_file_write(file, buf, count, ppos);
+ if (retval > 0) {
UDF_I_UCTIME(inode) = UDF_I_UMTIME(inode) = CURRENT_UTIME;
mark_inode_dirty(inode);
}
@@ -338,83 +347,19 @@ static int udf_open_file(struct inode * inode, struct file * filp)
}
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 */
+ llseek: udf_file_llseek,
+ read: generic_file_read,
+ write: udf_file_write,
+ ioctl: udf_ioctl,
+ mmap: generic_file_mmap,
+ open: udf_open_file,
+ release: udf_release_file,
+ fsync: udf_sync_file,
};
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 */
+ truncate: udf_truncate,
#endif
- NULL, /* permission */
- NULL /* revalidate */
};
diff --git a/fs/udf/fsync.c b/fs/udf/fsync.c
index b5c10c91b..e7d067e62 100644
--- a/fs/udf/fsync.c
+++ b/fs/udf/fsync.c
@@ -27,6 +27,7 @@
#include <linux/fs.h>
#include <linux/locks.h>
+#include <linux/smp_lock.h>
#include <linux/udf_fs.h>
#include "udf_i.h"
@@ -100,6 +101,7 @@ int udf_sync_file(struct file * file, struct dentry *dentry)
int wait, err = 0;
struct inode *inode = dentry->d_inode;
+ lock_kernel();
if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
{
/*
@@ -116,10 +118,6 @@ int udf_sync_file(struct file * file, struct dentry *dentry)
}
skip:
err |= udf_sync_inode (inode);
+ unlock_kernel();
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/inode.c b/fs/udf/inode.c
index 2ea1f980b..752a00339 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -56,6 +56,7 @@ static void udf_merge_extents(struct inode *,
static void udf_update_extents(struct inode *,
long_ad [EXTENT_MERGE_SIZE], int, int,
lb_addr, Uint32, struct buffer_head **);
+static int udf_get_block(struct inode *, long, struct buffer_head *, int);
/*
* udf_put_inode
@@ -96,7 +97,7 @@ void udf_delete_inode(struct inode * inode)
{
inode->i_size = 0;
if (inode->i_blocks)
- inode->i_op->truncate(inode);
+ udf_truncate(inode);
udf_free_inode(inode);
}
@@ -117,6 +118,30 @@ static int udf_alloc_block(struct inode *inode, Uint16 partition,
return result;
}
+static int udf_writepage(struct dentry *dentry, struct page *page)
+{
+ return block_write_full_page(page,udf_get_block);
+}
+static int udf_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,udf_get_block);
+}
+static int udf_prepare_write(struct page *page, unsigned from, unsigned to)
+{
+ return block_prepare_write(page,from,to,udf_get_block);
+}
+static int udf_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,udf_get_block);
+}
+static struct address_space_operations udf_aops = {
+ readpage: udf_readpage,
+ writepage: udf_writepage,
+ prepare_write: udf_prepare_write,
+ commit_write: generic_commit_write,
+ bmap: udf_bmap
+};
+
void udf_expand_file_adinicb(struct file * filp, int newsize, int * err)
{
struct inode * inode = filp->f_dentry->d_inode;
@@ -124,12 +149,13 @@ void udf_expand_file_adinicb(struct file * filp, int newsize, int * err)
struct page *page;
unsigned long kaddr = 0;
+ /* from now on we have normal address_space methods */
+ inode->i_data.a_ops = &udf_aops;
+
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;
}
@@ -156,14 +182,12 @@ void udf_expand_file_adinicb(struct file * filp, int newsize, int * err)
mark_buffer_dirty(bh, 1);
udf_release_data(bh);
- block_write_full_page(filp->f_dentry, page);
+ inode->i_data.a_ops->writepage(filp->f_dentry, page);
UnlockPage(page);
page_cache_release(page);
mark_inode_dirty(inode);
inode->i_version ++;
- inode->i_op = &udf_file_inode_operations;
- filp->f_op = inode->i_op->default_file_ops;
}
struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int *err)
@@ -251,34 +275,7 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
return dbh;
}
-struct buffer_head * udf_getblk(struct inode * inode, long block,
- int create, int * err)
-{
- struct buffer_head dummy;
- int error;
-
- dummy.b_state = 0;
- dummy.b_blocknr = -1000;
- error = udf_get_block(inode, block, &dummy, create);
- *err = error;
- if (!error & buffer_mapped(&dummy))
- {
- struct buffer_head *bh;
- bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
- if (buffer_new(&dummy))
- {
- 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);
- }
- return bh;
- }
- return NULL;
-}
-
-int udf_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create)
+static int udf_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create)
{
int err, new;
struct buffer_head *bh;
@@ -335,6 +332,33 @@ abort_negative:
goto abort;
}
+struct buffer_head * udf_getblk(struct inode * inode, long block,
+ int create, int * err)
+{
+ struct buffer_head dummy;
+ int error;
+
+ dummy.b_state = 0;
+ dummy.b_blocknr = -1000;
+ error = udf_get_block(inode, block, &dummy, create);
+ *err = error;
+ if (!error & buffer_mapped(&dummy))
+ {
+ struct buffer_head *bh;
+ bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
+ if (buffer_new(&dummy))
+ {
+ 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);
+ }
+ return bh;
+ }
+ return NULL;
+}
+
static struct buffer_head * inode_getblk(struct inode * inode, long block,
int *err, long *phys, int *new)
{
@@ -1061,9 +1085,10 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
case FILE_TYPE_NONE:
{
if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
- inode->i_op = &udf_file_inode_operations_adinicb;
+ inode->i_data.a_ops = &udf_adinicb_aops;
else
- inode->i_op = &udf_file_inode_operations;
+ inode->i_data.a_ops = &udf_aops;
+ inode->i_op = &udf_file_inode_operations;
inode->i_mode |= S_IFREG;
break;
}
@@ -1084,7 +1109,8 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
}
case FILE_TYPE_SYMLINK:
{
- inode->i_op = &udf_symlink_inode_operations;
+ inode->i_data.a_ops = &udf_symlink_aops;
+ inode->i_op = &page_symlink_inode_operations;
inode->i_mode = S_IFLNK|S_IRWXUGO;
break;
}
@@ -1953,58 +1979,3 @@ 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/namei.c b/fs/udf/namei.c
index 1f54833e4..aff491ef5 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -642,7 +642,8 @@ int udf_create(struct inode *dir, struct dentry *dentry, int mode)
if (!inode)
return err;
- inode->i_op = &udf_file_inode_operations_adinicb;
+ inode->i_data.a_ops = &udf_adinicb_aops;
+ inode->i_op = &udf_file_inode_operations;
inode->i_mode = mode;
mark_inode_dirty(inode);
@@ -970,7 +971,8 @@ int udf_symlink(struct inode * dir, struct dentry * dentry, const char * symname
goto out;
inode->i_mode = S_IFLNK | S_IRWXUGO;
- inode->i_op = &udf_symlink_inode_operations;
+ inode->i_data.a_ops = &udf_symlink_aops;
+ inode->i_op = &page_symlink_inode_operations;
bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
ea = bh->b_data + udf_file_entry_alloc_offset(inode);
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
index 6e5dd233a..5a286ce84 100644
--- a/fs/udf/symlink.c
+++ b/fs/udf/symlink.c
@@ -121,23 +121,6 @@ out:
/*
* symlinks can't do much...
*/
-struct inode_operations udf_symlink_inode_operations = {
- NULL, /* no file-operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- page_readlink, /* readlink */
- page_follow_link, /* follow_link */
- NULL, /* get_block */
- udf_symlink_filler, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
+struct address_space_operations udf_symlink_aops = {
+ readpage: udf_symlink_filler,
};
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index 4054da721..f5602dc0e 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -188,21 +188,10 @@ void udf_truncate(struct inode * inode)
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return;
- udf_trunc(inode);
-
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty(inode);
-}
-
-void udf_truncate_adinicb(struct inode * inode)
-{
- if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)))
- return;
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
- return;
-
- UDF_I_LENALLOC(inode) = inode->i_size;
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+ UDF_I_LENALLOC(inode) = inode->i_size;
+ else
+ udf_trunc(inode);
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 171cd0d75..39418f730 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -63,8 +63,8 @@ struct super_block;
extern struct inode_operations udf_dir_inode_operations;
extern struct inode_operations udf_file_inode_operations;
-extern struct inode_operations udf_file_inode_operations_adinicb;
-extern struct inode_operations udf_symlink_inode_operations;
+extern struct address_space_operations udf_adinicb_aops;
+extern struct address_space_operations udf_symlink_aops;
struct udf_fileident_bh
{
@@ -137,9 +137,6 @@ extern int udf_sync_inode(struct inode *);
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 *);
@@ -187,14 +184,12 @@ 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 *);
/* balloc.c */
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 *);
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index a828f3036..0e4e3a720 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -178,18 +178,8 @@ int ufs_check_dir_entry (const char * function, struct inode * dir,
}
static struct file_operations ufs_dir_operations = {
- NULL, /* lseek */
- NULL, /* read */
- NULL, /* write */
- ufs_readdir, /* readdir */
- NULL, /* select */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* open */
- NULL, /* flush */
- NULL, /* release */
- file_fsync, /* fsync */
- NULL, /* fasync */
+ readdir: ufs_readdir,
+ fsync: file_fsync,
};
struct inode_operations ufs_dir_inode_operations = {
@@ -205,9 +195,6 @@ struct inode_operations ufs_dir_inode_operations = {
ufs_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
NULL, /* truncate */
ufs_permission, /* permission */
NULL /* revalidate */
diff --git a/fs/ufs/file.c b/fs/ufs/file.c
index fa4734d23..384774cc5 100644
--- a/fs/ufs/file.c
+++ b/fs/ufs/file.c
@@ -36,11 +36,6 @@
#include <linux/mm.h>
#include <linux/pagemap.h>
-#define NBUF 32
-
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-
/*
* Make sure the offset never goes beyond the 32-bit mark..
*/
@@ -72,86 +67,18 @@ static long long ufs_file_lseek(
return retval;
}
-static inline void remove_suid(struct inode *inode)
-{
- unsigned int mode;
-
- /* set S_IGID if S_IXGRP is set, and always set S_ISUID */
- mode = (inode->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID;
-
- /* was any of the uid bits set? */
- mode &= inode->i_mode;
- if (mode && !suser()) {
- inode->i_mode &= ~mode;
- mark_inode_dirty(inode);
- }
-}
-
-/*
- * Write to a file (through the page cache).
- */
-static ssize_t
-ufs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
-{
- ssize_t retval;
-
- retval = generic_file_write(file, buf, count,
- ppos, block_write_partial_page);
- if (retval > 0) {
- struct inode *inode = file->f_dentry->d_inode;
- remove_suid(inode);
- inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- mark_inode_dirty(inode);
- }
- return retval;
-}
-
-/*
- * Called when an inode is released. Note that this is different
- * from ufs_open: open gets called at every open, but release
- * gets called only when /all/ the files are closed.
- */
-static int ufs_release_file (struct inode * inode, struct file * filp)
-{
- return 0;
-}
-
/*
* We have mostly NULL's here: the current defaults are ok for
* the ufs filesystem.
*/
static struct file_operations ufs_file_operations = {
- ufs_file_lseek, /* lseek */
- generic_file_read, /* read */
- ufs_file_write, /* write */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl */
- generic_file_mmap, /* mmap */
- NULL, /* no special open is needed */
- NULL, /* flush */
- ufs_release_file, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
+ llseek: ufs_file_lseek,
+ read: generic_file_read,
+ write: generic_file_write,
+ mmap: generic_file_mmap,
};
struct inode_operations ufs_file_inode_operations = {
- &ufs_file_operations,/* default file operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- ufs_getfrag_block, /* get_block */
- block_read_full_page, /* readpage */
- block_write_full_page, /* writepage */
- ufs_truncate, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
+ &ufs_file_operations,
+ truncate: ufs_truncate,
};
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 333186247..de2eec9a8 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -395,7 +395,7 @@ out:
return result;
}
-int ufs_getfrag_block (struct inode *inode, long fragment, struct buffer_head *bh_result, int create)
+static int ufs_getfrag_block (struct inode *inode, long fragment, struct buffer_head *bh_result, int create)
{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
@@ -540,6 +540,30 @@ struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment,
return NULL;
}
+static int ufs_writepage(struct dentry *dentry, struct page *page)
+{
+ return block_write_full_page(page,ufs_getfrag_block);
+}
+static int ufs_readpage(struct dentry *dentry, struct page *page)
+{
+ return block_read_full_page(page,ufs_getfrag_block);
+}
+static int ufs_prepare_write(struct page *page, unsigned from, unsigned to)
+{
+ return block_prepare_write(page,from,to,ufs_getfrag_block);
+}
+static int ufs_bmap(struct address_space *mapping, long block)
+{
+ return generic_block_bmap(mapping,block,ufs_getfrag_block);
+}
+struct address_space_operations ufs_aops = {
+ readpage: ufs_readpage,
+ writepage: ufs_writepage,
+ prepare_write: ufs_prepare_write,
+ commit_write: generic_commit_write,
+ bmap: ufs_bmap
+};
+
void ufs_read_inode (struct inode * inode)
{
struct super_block * sb;
@@ -619,15 +643,19 @@ void ufs_read_inode (struct inode * inode)
inode->i_op = NULL;
- if (S_ISREG(inode->i_mode))
+ if (S_ISREG(inode->i_mode)) {
inode->i_op = &ufs_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
+ inode->i_mapping->a_ops = &ufs_aops;
+ } else if (S_ISDIR(inode->i_mode))
inode->i_op = &ufs_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = inode->i_blocks
- ?&ufs_symlink_inode_operations
- :&ufs_fast_symlink_inode_operations;
- else
+ else if (S_ISLNK(inode->i_mode)) {
+ if (!inode->i_blocks)
+ inode->i_op = &ufs_fast_symlink_inode_operations;
+ else {
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_mapping->a_ops = &ufs_aops;
+ }
+ } else
init_special_inode(inode, inode->i_mode,
SWAB32(ufs_inode->ui_u2.ui_addr.ui_db[0]));
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index 33413b8cd..71198abc4 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -424,6 +424,7 @@ int ufs_create (struct inode * dir, struct dentry * dentry, int mode)
if (!inode)
return err;
inode->i_op = &ufs_file_inode_operations;
+ inode->i_mapping->a_ops = &ufs_aops;
inode->i_mode = mode;
mark_inode_dirty(inode);
bh = ufs_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
@@ -776,7 +777,8 @@ int ufs_symlink (struct inode * dir, struct dentry * dentry,
if (l > sb->u.ufs_sb.s_uspi->s_maxsymlinklen) {
/* slow symlink */
- inode->i_op = &ufs_symlink_inode_operations;
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_mapping->a_ops = &ufs_aops;
err = block_symlink(inode, symname, l);
if (err)
goto out_no_entry;
diff --git a/fs/ufs/symlink.c b/fs/ufs/symlink.c
index 06ee82740..4550f44cf 100644
--- a/fs/ufs/symlink.c
+++ b/fs/ufs/symlink.c
@@ -1,6 +1,8 @@
/*
* linux/fs/ufs/symlink.c
*
+ * Only fast symlinks left here - the rest is done by generic code. AV, 1999
+ *
* Copyright (C) 1998
* Daniel Pirkl <daniel.pirkl@emai.cz>
* Charles University, Faculty of Mathematics and Physics
@@ -24,7 +26,6 @@
*/
#include <linux/fs.h>
-#include <linux/ufs_fs.h>
static int ufs_readlink(struct dentry *dentry, char *buffer, int buflen)
{
@@ -42,10 +43,3 @@ struct inode_operations ufs_fast_symlink_inode_operations = {
readlink: ufs_readlink,
follow_link: ufs_follow_link,
};
-
-struct inode_operations ufs_symlink_inode_operations = {
- readlink: page_readlink,
- follow_link: page_follow_link,
- get_block: ufs_getfrag_block,
- readpage: block_read_full_page
-};
diff --git a/fs/umsdos/Makefile b/fs/umsdos/Makefile
index 8856feba7..f1b7b3ed4 100644
--- a/fs/umsdos/Makefile
+++ b/fs/umsdos/Makefile
@@ -8,8 +8,7 @@
# Note 2: the CFLAGS definitions are now in the main makefile.
O_TARGET := umsdos.o
-O_OBJS := dir.o inode.o ioctl.o mangle.o namei.o \
- rdir.o symlink.o emd.o check.o
+O_OBJS := dir.o inode.o ioctl.o mangle.o namei.o rdir.o emd.o check.o
M_OBJS := $(O_TARGET)
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index af875aa79..366657ae6 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -802,17 +802,9 @@ out_noread:
static struct file_operations umsdos_dir_operations =
{
- NULL, /* lseek - default */
- dummy_dir_read, /* read */
- NULL, /* write - bad */
- UMSDOS_readdir, /* readdir */
- NULL, /* poll - default */
- UMSDOS_ioctl_dir, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* fsync */
+ read: dummy_dir_read,
+ readdir: UMSDOS_readdir,
+ ioctl: UMSDOS_ioctl_dir,
};
struct inode_operations umsdos_dir_inode_operations =
@@ -827,12 +819,4 @@ struct inode_operations umsdos_dir_inode_operations =
UMSDOS_rmdir, /* rmdir */
UMSDOS_mknod, /* mknod */
UMSDOS_rename, /* rename */
- NULL, /* readlink */
- NULL, /* followlink */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c
index 252f8a48b..fb8dc03ff 100644
--- a/fs/umsdos/inode.c
+++ b/fs/umsdos/inode.c
@@ -155,7 +155,8 @@ dentry, f_pos));
} else if (S_ISDIR (inode->i_mode)) {
umsdos_setup_dir(dentry);
} else if (S_ISLNK (inode->i_mode)) {
- inode->i_op = &umsdos_symlink_inode_operations;
+ /* address_space operations already set */
+ inode->i_op = &page_symlink_inode_operations;
} else
init_special_inode(inode, inode->i_mode,
kdev_t_to_nr(inode->i_rdev));
diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c
index 2b972a524..a466a9396 100644
--- a/fs/umsdos/rdir.c
+++ b/fs/umsdos/rdir.c
@@ -220,17 +220,9 @@ out:
*/
static struct file_operations umsdos_rdir_operations =
{
- NULL, /* lseek - default */
- dummy_dir_read, /* read */
- NULL, /* write - bad */
- UMSDOS_rreaddir, /* readdir */
- NULL, /* poll - default */
- UMSDOS_ioctl_dir, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* fsync */
+ read: dummy_dir_read,
+ readdir: UMSDOS_rreaddir,
+ ioctl: UMSDOS_ioctl_dir,
};
struct inode_operations umsdos_rdir_inode_operations =
@@ -245,12 +237,4 @@ struct inode_operations umsdos_rdir_inode_operations =
UMSDOS_rrmdir, /* rmdir */
NULL, /* mknod */
msdos_rename, /* rename */
- NULL, /* readlink */
- NULL, /* followlink */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* get_block */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
diff --git a/fs/umsdos/symlink.c b/fs/umsdos/symlink.c
deleted file mode 100644
index 7bcd09e44..000000000
--- a/fs/umsdos/symlink.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * linux/fs/umsdos/file.c
- *
- * Written 1992 by Jacques Gelinas
- * inspired from linux/fs/msdos/file.c Werner Almesberger
- *
- * Extended MS-DOS regular file handling primitives
- *
- * Wow. It looks like we could support them on FAT with little (if any)
- * problems. Oh, well...
- */
-
-#include <linux/fs.h>
-#include <linux/msdos_fs.h>
-
-struct inode_operations umsdos_symlink_inode_operations =
-{
- readlink: page_readlink,
- follow_link: page_follow_link,
- get_block: fat_get_block,
- readpage: block_read_full_page
-};
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index 0dea64e75..0aced9465 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -1276,14 +1276,6 @@ struct inode_operations vfat_dir_inode_operations = {
vfat_rmdir, /* rmdir */
NULL, /* mknod */
vfat_rename, /* rename */
- NULL, /* readlink */
- NULL, /* followlink */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL /* revalidate */
};
struct super_block *vfat_read_super(struct super_block *sb,void *data,