summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-01-29 01:41:54 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-01-29 01:41:54 +0000
commitf969d69ba9f952e5bdd38278e25e26a3e4a61a70 (patch)
treeb3530d803df59d726afaabebc6626987dee1ca05 /fs
parenta10ce7ef2066b455d69187643ddf2073bfc4db24 (diff)
Merge with 2.3.27.
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.in18
-rw-r--r--fs/Makefile10
-rw-r--r--fs/adfs/inode.c2
-rw-r--r--fs/bfs/.cvsignore2
-rw-r--r--fs/bfs/Makefile14
-rw-r--r--fs/bfs/bfs_defs.h15
-rw-r--r--fs/bfs/dir.c382
-rw-r--r--fs/bfs/file.c76
-rw-r--r--fs/bfs/inode.c389
-rw-r--r--fs/binfmt_elf.c9
-rw-r--r--fs/binfmt_em86.c25
-rw-r--r--fs/binfmt_misc.c22
-rw-r--r--fs/buffer.c149
-rw-r--r--fs/coda/file.c2
-rw-r--r--fs/coda/sysctl.c71
-rw-r--r--fs/dcache.c5
-rw-r--r--fs/exec.c21
-rw-r--r--fs/ext2/acl.c10
-rw-r--r--fs/ext2/balloc.c16
-rw-r--r--fs/ext2/bitmap.c4
-rw-r--r--fs/ext2/dir.c9
-rw-r--r--fs/ext2/file.c31
-rw-r--r--fs/ext2/fsync.c13
-rw-r--r--fs/ext2/ialloc.c16
-rw-r--r--fs/ext2/inode.c33
-rw-r--r--fs/ext2/ioctl.c11
-rw-r--r--fs/ext2/namei.c10
-rw-r--r--fs/ext2/super.c21
-rw-r--r--fs/ext2/symlink.c9
-rw-r--r--fs/ext2/truncate.c17
-rw-r--r--fs/fat/file.c11
-rw-r--r--fs/fat/inode.c191
-rw-r--r--fs/file.c8
-rw-r--r--fs/filesystems.c5
-rw-r--r--fs/hfs/file.c1
-rw-r--r--fs/inode.c11
-rw-r--r--fs/isofs/inode.c2
-rw-r--r--fs/lockd/mon.c10
-rw-r--r--fs/minix/bitmap.c7
-rw-r--r--fs/ncpfs/dir.c692
-rw-r--r--fs/ncpfs/file.c26
-rw-r--r--fs/ncpfs/inode.c48
-rw-r--r--fs/ncpfs/ioctl.c12
-rw-r--r--fs/ncpfs/mmap.c23
-rw-r--r--fs/ncpfs/ncplib_kernel.c32
-rw-r--r--fs/ncpfs/ncplib_kernel.h73
-rw-r--r--fs/ncpfs/sock.c28
-rw-r--r--fs/ncpfs/symlink.c6
-rw-r--r--fs/nfs/dir.c62
-rw-r--r--fs/nfs/inode.c2
-rw-r--r--fs/nfs/mount_clnt.c2
-rw-r--r--fs/nfs/nfs3xdr.c2
-rw-r--r--fs/nfs/read.c8
-rw-r--r--fs/nfs/write.c12
-rw-r--r--fs/nfsd/nfsctl.c24
-rw-r--r--fs/nfsd/nfsfh.c104
-rw-r--r--fs/nfsd/stats.c5
-rw-r--r--fs/nfsd/vfs.c9
-rw-r--r--fs/open.c4
-rw-r--r--fs/proc/Makefile4
-rw-r--r--fs/proc/array.c1166
-rw-r--r--fs/proc/base.c1097
-rw-r--r--fs/proc/fd.c199
-rw-r--r--fs/proc/generic.c27
-rw-r--r--fs/proc/inode-alloc.txt46
-rw-r--r--fs/proc/inode.c199
-rw-r--r--fs/proc/kcore.c388
-rw-r--r--fs/proc/link.c205
-rw-r--r--fs/proc/mem.c354
-rw-r--r--fs/proc/net.c124
-rw-r--r--fs/proc/proc_misc.c692
-rw-r--r--fs/proc/procfs_syms.c19
-rw-r--r--fs/proc/root.c585
-rw-r--r--fs/proc/scsi.c219
-rw-r--r--fs/proc/sysvipc.c141
-rw-r--r--fs/read_write.c8
-rw-r--r--fs/romfs/inode.c18
-rw-r--r--fs/smbfs/cache.c33
-rw-r--r--fs/smbfs/file.c6
-rw-r--r--fs/super.c6
-rw-r--r--fs/sysv/namei.c2
-rw-r--r--fs/udf/balloc.c12
-rw-r--r--fs/udf/dir.c7
-rw-r--r--fs/udf/directory.c4
-rw-r--r--fs/udf/file.c42
-rw-r--r--fs/udf/inode.c115
-rw-r--r--fs/udf/lowlevel.c13
-rw-r--r--fs/udf/misc.c26
-rw-r--r--fs/udf/namei.c209
-rw-r--r--fs/udf/super.c19
-rw-r--r--fs/udf/truncate.c2
-rw-r--r--fs/udf/udfdecl.h12
-rw-r--r--fs/udf/udfend.h8
-rw-r--r--fs/udf/udftime.c339
-rw-r--r--fs/ufs/balloc.c2
-rw-r--r--fs/ufs/dir.c2
-rw-r--r--fs/ufs/inode.c2
-rw-r--r--fs/ufs/super.c4
-rw-r--r--fs/ufs/truncate.c10
-rw-r--r--fs/ufs/util.h1
100 files changed, 4437 insertions, 4762 deletions
diff --git a/fs/Config.in b/fs/Config.in
index 78af8d3d4..b15be4a0d 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -14,6 +14,12 @@ fi
tristate 'Amiga FFS filesystem support' CONFIG_AFFS_FS
tristate 'Apple Macintosh filesystem support (EXPERIMENTAL)' CONFIG_HFS_FS
# msdos filesystems
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'BFS filesystem (read only) support (EXPERIMENTAL)' CONFIG_BFS_FS
+ if [ "$CONFIG_BFS_FS" != "n" ]; then
+ bool ' BFS filesystem write support (DANGEROUS)' CONFIG_BFS_FS_WRITE
+ fi
+fi
tristate 'DOS FAT fs support' CONFIG_FAT_FS
dep_tristate ' MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
dep_tristate ' UMSDOS: Unix-like filesystem on top of standard MSDOS filesystem' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
@@ -84,15 +90,15 @@ if [ "$CONFIG_INET" = "y" ]; then
bool ' Emulate SUN NFS server' CONFIG_NFSD_SUN
fi
if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
- define_bool CONFIG_SUNRPC y
- define_bool CONFIG_LOCKD y
+ define_tristate CONFIG_SUNRPC y
+ define_tristate CONFIG_LOCKD y
else
if [ "$CONFIG_NFS_FS" = "m" -o "$CONFIG_NFSD" = "m" ]; then
- define_bool CONFIG_SUNRPC m
- define_bool CONFIG_LOCKD m
+ define_tristate CONFIG_SUNRPC m
+ define_tristate CONFIG_LOCKD m
else
- define_bool CONFIG_SUNRPC n
- define_bool CONFIG_LOCKD n
+ define_tristate CONFIG_SUNRPC n
+ define_tristate CONFIG_LOCKD n
fi
fi
tristate 'SMB filesystem support (to mount WfW shares etc.)' CONFIG_SMB_FS
diff --git a/fs/Makefile b/fs/Makefile
index 8bfbd050b..88810457d 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -18,7 +18,7 @@ O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \
MOD_LIST_NAME := FS_MODULES
ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
hpfs sysv smbfs ncpfs ufs efs affs romfs autofs hfs lockd \
- nfsd nls devpts adfs partitions qnx4 udf
+ nfsd nls devpts adfs partitions qnx4 udf bfs
SUB_DIRS := partitions
@@ -84,6 +84,14 @@ MOD_TO_LIST += openpromfs.o
endif
endif
+ifeq ($(CONFIG_BFS_FS),y)
+SUB_DIRS += bfs
+else
+ ifeq ($(CONFIG_BFS_FS),m)
+ MOD_SUB_DIRS += bfs
+ endif
+endif
+
ifeq ($(CONFIG_ISO9660_FS),y)
SUB_DIRS += isofs
else
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 6c8814567..b33044af3 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -181,7 +181,7 @@ void adfs_read_inode (struct inode *inode)
inode->i_nlink = 2;
inode->i_size = ADFS_NEWDIR_SIZE;
inode->i_blksize = PAGE_SIZE;
- inode->i_blocks = inode->i_size / sb->s_blocksize;
+ inode->i_blocks = inode->i_size >> sb->s_blocksize_bits;
inode->i_mtime =
inode->i_atime =
inode->i_ctime = 0;
diff --git a/fs/bfs/.cvsignore b/fs/bfs/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/fs/bfs/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/fs/bfs/Makefile b/fs/bfs/Makefile
new file mode 100644
index 000000000..0aeda0cca
--- /dev/null
+++ b/fs/bfs/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for BFS filesystem.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main Makefile...
+
+O_TARGET := bfs.o
+O_OBJS := inode.o file.o dir.o
+M_OBJS := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff --git a/fs/bfs/bfs_defs.h b/fs/bfs/bfs_defs.h
new file mode 100644
index 000000000..54d7dad29
--- /dev/null
+++ b/fs/bfs/bfs_defs.h
@@ -0,0 +1,15 @@
+#define su_lasti u.bfs_sb.si_lasti
+#define su_blocks u.bfs_sb.si_blocks
+#define su_freeb u.bfs_sb.si_freeb
+#define su_freei u.bfs_sb.si_freei
+#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
+
+#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
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
new file mode 100644
index 000000000..8aa200451
--- /dev/null
+++ b/fs/bfs/dir.c
@@ -0,0 +1,382 @@
+/*
+ * fs/bfs/dir.c
+ * BFS directory operations.
+ * Copyright (C) 1999 Tigran Aivazian <tigran@ocston.org>
+ */
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/bfs_fs.h>
+#include <linux/locks.h>
+
+#include "bfs_defs.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino);
+static struct buffer_head * bfs_find_entry(struct inode * dir,
+ const char * name, int namelen, struct bfs_dirent ** res_dir);
+
+static ssize_t bfs_dir_read(struct file * f, char * buf, size_t count, loff_t *ppos)
+{
+ return -EISDIR;
+}
+
+static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
+{
+ struct inode * dir = f->f_dentry->d_inode;
+ struct buffer_head * bh;
+ struct bfs_dirent * de;
+ kdev_t dev = dir->i_dev;
+ unsigned int offset;
+ 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);
+ 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);
+ return -EBADF;
+ }
+
+ while (f->f_pos < dir->i_size) {
+ offset = f->f_pos & (BFS_BSIZE-1);
+ block = dir->iu_sblock + (f->f_pos >> BFS_BSIZE_BITS);
+ bh = bread(dev, block, BFS_BSIZE);
+ if (!bh) {
+ f->f_pos += BFS_BSIZE - offset;
+ continue;
+ }
+ do {
+ de = (struct bfs_dirent *)(bh->b_data + offset);
+ if (de->ino) {
+ int size = strnlen(de->name, BFS_NAMELEN);
+ if (filldir(dirent, de->name, size, f->f_pos, de->ino) < 0) {
+ brelse(bh);
+ return 0;
+ }
+ }
+ offset += BFS_DIRENT_SIZE;
+ f->f_pos += BFS_DIRENT_SIZE;
+ } while (offset < BFS_BSIZE && f->f_pos < dir->i_size);
+ brelse(bh);
+ }
+
+ UPDATE_ATIME(dir);
+ return 0;
+}
+
+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,
+ check_media_change: NULL,
+ revalidate: NULL,
+};
+
+extern void dump_imap(const char *, struct super_block *);
+
+static int bfs_create(struct inode * dir, struct dentry * dentry, int mode)
+{
+ int err;
+ struct inode * inode;
+ struct super_block * s = dir->i_sb;
+ unsigned long ino;
+
+ inode = get_empty_inode();
+ if (!inode)
+ return -ENOSPC;
+ inode->i_sb = s;
+ ino = find_first_zero_bit(s->su_imap, s->su_lasti);
+ if (ino > s->su_lasti) {
+ iput(inode);
+ return -ENOSPC;
+ }
+ set_bit(ino, s->su_imap);
+ s->su_freei--;
+ inode->i_dev = s->s_dev;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
+ 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_mode = mode;
+ inode->i_ino = inode->iu_dsk_ino = ino;
+ inode->iu_sblock = inode->iu_eblock = 0;
+ insert_inode_hash(inode);
+ mark_inode_dirty(inode);
+ dump_imap("create",s);
+
+ err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, inode->i_ino);
+ if (err) {
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ iput(inode);
+ return err;
+ }
+ d_instantiate(dentry, inode);
+ return 0;
+}
+
+static struct dentry * bfs_lookup(struct inode * dir, struct dentry * dentry)
+{
+ struct inode * inode = NULL;
+ struct buffer_head * bh;
+ struct bfs_dirent * de;
+
+ if (dentry->d_name.len > BFS_NAMELEN)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
+ if (bh) {
+ unsigned long ino = le32_to_cpu(de->ino);
+ brelse(bh);
+ inode = iget(dir->i_sb, ino);
+ if (!inode)
+ return ERR_PTR(-EACCES);
+ }
+ d_add(dentry, inode);
+ return NULL;
+}
+
+static int bfs_link(struct dentry * old, struct inode * dir, struct dentry * new)
+{
+ struct inode * inode = old->d_inode;
+ int err;
+
+ if (S_ISDIR(inode->i_mode))
+ return -EPERM;
+
+ err = bfs_add_entry(dir, new->d_name.name, new->d_name.len, inode->i_ino);
+ if (err)
+ return err;
+ inode->i_nlink++;
+ inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ inode->i_count++;
+ d_instantiate(new, inode);
+ return 0;
+}
+
+
+static int bfs_unlink(struct inode * dir, struct dentry * dentry)
+{
+ int error = -ENOENT;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct bfs_dirent * de;
+
+ inode = dentry->d_inode;
+ bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
+ if (!bh || de->ino != inode->i_ino)
+ 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);
+ inode->i_nlink = 1;
+ }
+ de->ino = 0;
+ dir->i_version = ++event;
+ mark_buffer_dirty(bh, 1);
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(dir);
+ inode->i_nlink--;
+ inode->i_ctime = dir->i_ctime;
+ mark_inode_dirty(inode);
+ d_delete(dentry);
+ error = 0;
+
+out_brelse:
+ brelse(bh);
+ return error;
+}
+
+static int bfs_rename(struct inode * old_dir, struct dentry * old_dentry,
+ struct inode * new_dir, struct dentry * new_dentry)
+{
+ struct inode * old_inode, * new_inode;
+ struct buffer_head * old_bh, * new_bh;
+ struct bfs_dirent * old_de, * new_de;
+ int error = -ENOENT;
+
+ old_bh = new_bh = NULL;
+ old_inode = old_dentry->d_inode;
+ if (S_ISDIR(old_inode->i_mode))
+ return -EINVAL;
+
+ old_bh = bfs_find_entry(old_dir,
+ old_dentry->d_name.name,
+ old_dentry->d_name.len, &old_de);
+
+ if (!old_bh || old_de->ino != old_inode->i_ino)
+ goto end_rename;
+
+ error = -EPERM;
+ new_inode = new_dentry->d_inode;
+ new_bh = bfs_find_entry(new_dir,
+ new_dentry->d_name.name,
+ new_dentry->d_name.len, &new_de);
+
+ if (new_bh && !new_inode) {
+ brelse(new_bh);
+ new_bh = NULL;
+ }
+ if (!new_bh) {
+ error = bfs_add_entry(new_dir,
+ new_dentry->d_name.name,
+ new_dentry->d_name.len, old_inode->i_ino);
+ if (error)
+ goto end_rename;
+ }
+ old_de->ino = 0;
+ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+ old_dir->i_version = ++event;
+ mark_inode_dirty(old_dir);
+ if (new_inode) {
+ new_inode->i_nlink--;
+ new_inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(new_inode);
+ }
+ mark_buffer_dirty(old_bh, 1);
+ error = 0;
+
+end_rename:
+ brelse(old_bh);
+ brelse(new_bh);
+ return error;
+}
+
+struct inode_operations bfs_dir_inops = {
+ default_file_ops: &bfs_dir_operations,
+ create: bfs_create,
+ lookup: bfs_lookup,
+ link: bfs_link,
+ unlink: bfs_unlink,
+ symlink: NULL,
+ mkdir: NULL,
+ rmdir: NULL,
+ mknod: NULL,
+ rename: bfs_rename,
+ readlink: NULL,
+ follow_link: NULL,
+ get_block: NULL,
+ readpage: NULL,
+ writepage: NULL,
+ flushpage: NULL,
+ truncate: NULL,
+ permission: NULL,
+ smap: NULL,
+ revalidate: NULL
+};
+
+static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino)
+{
+ struct buffer_head * bh;
+ struct bfs_dirent * de;
+ int block, sblock, eblock, off;
+ kdev_t dev;
+ int i;
+
+ DBG(KERN_ERR "BFS-fs: %s(%s,%d)\n", __FUNCTION__, name, namelen);
+
+ if (!namelen)
+ return -ENOENT;
+ if (namelen > BFS_NAMELEN)
+ return -ENAMETOOLONG;
+
+ dev = dir->i_dev;
+ sblock = dir->iu_sblock;
+ eblock = dir->iu_eblock;
+ for (block=sblock; block<=eblock; block++) {
+ bh = bread(dev, block, BFS_BSIZE);
+ if(!bh)
+ return -ENOSPC;
+ for (off=0; off<BFS_BSIZE; off+=BFS_DIRENT_SIZE) {
+ de = (struct bfs_dirent *)(bh->b_data + off);
+ if (!de->ino) {
+ if ((block-sblock)*BFS_BSIZE + off >= dir->i_size) {
+ dir->i_size += BFS_DIRENT_SIZE;
+ dir->i_ctime = CURRENT_TIME;
+ }
+ dir->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(dir);
+ dir->i_version = ++event;
+ de->ino = ino;
+ for (i=0; i<BFS_NAMELEN; i++)
+ de->name[i] = (i < namelen) ? name[i] : 0;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ return 0;
+ }
+ }
+ brelse(bh);
+ }
+ return -ENOSPC;
+}
+
+static inline int bfs_namecmp(int len, const char * name, const char * buffer)
+{
+ if (len < BFS_NAMELEN && buffer[len])
+ return 0;
+ return !memcmp(name, buffer, len);
+}
+
+static struct buffer_head * bfs_find_entry(struct inode * dir,
+ const char * name, int namelen, struct bfs_dirent ** res_dir)
+{
+ unsigned long block, offset;
+ struct buffer_head * bh;
+ struct bfs_sb_info * info;
+ struct bfs_dirent * de;
+
+ *res_dir = NULL;
+ info = &dir->i_sb->u.bfs_sb;
+ if (namelen > BFS_NAMELEN)
+ return NULL;
+ bh = NULL;
+ block = offset = 0;
+ while (block * BFS_BSIZE + offset < dir->i_size) {
+ if (!bh) {
+ bh = bread(dir->i_dev, dir->iu_sblock + block, BFS_BSIZE);
+ if (!bh) {
+ block++;
+ continue;
+ }
+ }
+ de = (struct bfs_dirent *)(bh->b_data + offset);
+ offset += BFS_DIRENT_SIZE;
+ if (de->ino && bfs_namecmp(namelen, name, de->name)) {
+ *res_dir = de;
+ return bh;
+ }
+ if (offset < bh->b_size)
+ continue;
+ brelse(bh);
+ bh = NULL;
+ offset = 0;
+ block++;
+ }
+ brelse(bh);
+ return NULL;
+}
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
new file mode 100644
index 000000000..4bc1ed99a
--- /dev/null
+++ b/fs/bfs/file.c
@@ -0,0 +1,76 @@
+/*
+ * fs/bfs/file.c
+ * BFS file operations.
+ * Copyright (C) 1999 Tigran Aivazian <tigran@ocston.org>
+ */
+
+#include <linux/fs.h>
+#include <linux/bfs_fs.h>
+#include "bfs_defs.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(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,
+ mmap: generic_file_mmap,
+ open: NULL,
+ flush: NULL,
+ release: NULL,
+ fsync: NULL,
+ fasync: NULL,
+ check_media_change: NULL,
+ revalidate: NULL,
+};
+
+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) {
+ 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;
+}
+
+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,
+ flushpage: block_flushpage,
+ truncate: NULL,
+ permission: NULL,
+ smap: NULL,
+ revalidate: NULL
+};
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
new file mode 100644
index 000000000..c0ee15dc4
--- /dev/null
+++ b/fs/bfs/inode.c
@@ -0,0 +1,389 @@
+/*
+ * fs/bfs/inode.c
+ * BFS superblock and inode operations.
+ * Copyright (C) 1999 Tigran Aivazian <tigran@ocston.org>
+ * 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>
+#include <linux/init.h>
+#include <linux/locks.h>
+#include <linux/bfs_fs.h>
+
+#include <asm/uaccess.h>
+
+#include "bfs_defs.h"
+
+MODULE_AUTHOR("Tigran A. Aivazian");
+MODULE_DESCRIPTION("UnixWare BFS filesystem for Linux");
+EXPORT_NO_SYMBOLS;
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+void dump_imap(const char *prefix, struct super_block * s);
+
+static void bfs_read_inode(struct inode * inode)
+{
+ unsigned long ino = inode->i_ino;
+ kdev_t dev = inode->i_dev;
+ struct bfs_inode * di;
+ struct buffer_head * bh;
+ 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);
+ make_bad_inode(inode);
+ 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);
+ make_bad_inode(inode);
+ return;
+ }
+
+ off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
+ di = (struct bfs_inode *)bh->b_data + off;
+
+ inode->i_mode = 0x0000FFFF & di->i_mode;
+ if (di->i_vtype == BFS_VDIR) {
+ inode->i_mode |= S_IFDIR;
+ inode->i_op = &bfs_dir_inops;
+ } else if (di->i_vtype == BFS_VREG) {
+ inode->i_mode |= S_IFREG;
+ inode->i_op = &bfs_file_inops;
+ } else
+ inode->i_op = NULL;
+
+ inode->i_uid = di->i_uid;
+ inode->i_gid = di->i_gid;
+ inode->i_nlink = di->i_nlink;
+ inode->i_size = BFS_FILESIZE(di);
+ inode->i_blocks = BFS_FILEBLOCKS(di);
+ inode->i_blksize = PAGE_SIZE;
+ inode->i_atime = di->i_atime;
+ inode->i_mtime = di->i_mtime;
+ inode->i_ctime = di->i_ctime;
+ inode->i_rdev = 0; /* BFS doesn't have special nodes */
+ inode->iu_dsk_ino = di->i_ino; /* can be 0 so we store a copy */
+ inode->iu_sblock = di->i_sblock;
+ inode->iu_eblock = di->i_eblock;
+
+ brelse(bh);
+}
+
+static void bfs_write_inode(struct inode * inode)
+{
+ unsigned long ino = inode->i_ino;
+ kdev_t dev = inode->i_dev;
+ struct bfs_inode * di;
+ struct buffer_head * bh;
+ 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);
+ 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);
+ return;
+ }
+
+ off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK;
+ di = (struct bfs_inode *)bh->b_data + off;
+
+ if (inode->i_ino == BFS_ROOT_INO)
+ di->i_vtype = BFS_VDIR;
+ else
+ di->i_vtype = BFS_VREG;
+
+ di->i_ino = inode->i_ino;
+ di->i_mode = inode->i_mode;
+ di->i_uid = inode->i_uid;
+ di->i_gid = inode->i_gid;
+ di->i_nlink = inode->i_nlink;
+ di->i_atime = inode->i_atime;
+ di->i_mtime = inode->i_mtime;
+ di->i_ctime = inode->i_ctime;
+ di->i_sblock = inode->iu_sblock;
+ di->i_eblock = inode->iu_eblock;
+ di->i_eoffset = di->i_sblock * BFS_BSIZE + inode->i_size - 1;
+
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+}
+
+static void bfs_delete_inode(struct inode * inode)
+{
+ unsigned long ino = inode->i_ino;
+ kdev_t dev = inode->i_dev;
+ struct bfs_inode * di;
+ struct buffer_head * bh;
+ int block, off;
+ struct super_block * s = inode->i_sb;
+
+ DBG(KERN_ERR "%s(ino=%08lx)\n", __FUNCTION__, inode->i_ino);
+
+ if (!inode)
+ 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);
+ return;
+ }
+
+ inode->i_size = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(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);
+ return;
+ }
+ off = (ino - BFS_ROOT_INO)%BFS_INODES_PER_BLOCK;
+ di = (struct bfs_inode *)bh->b_data + off;
+ if (di->i_ino) {
+ s->su_freeb += BFS_FILEBLOCKS(di);
+ s->su_freei++;
+ clear_bit(di->i_ino, s->su_imap);
+ dump_imap("delete_inode", s);
+ }
+ di->i_ino = 0;
+ di->i_sblock = 0;
+ mark_buffer_dirty(bh, 1);
+ brelse(bh);
+ clear_inode(inode);
+}
+
+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;
+}
+
+static int bfs_statfs(struct super_block *s, struct statfs *buf, int bufsiz)
+{
+ struct statfs tmp;
+
+ tmp.f_type = BFS_MAGIC;
+ tmp.f_bsize = s->s_blocksize;
+ tmp.f_blocks = s->su_blocks;
+ tmp.f_bfree = tmp.f_bavail = s->su_freeb;
+ tmp.f_files = s->su_lasti + 1 - BFS_ROOT_INO;
+ tmp.f_ffree = s->su_freei;
+ tmp.f_fsid.val[0] = s->s_dev;
+ tmp.f_namelen = BFS_NAMELEN;
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+}
+
+static void bfs_write_super(struct super_block *s)
+{
+ if (!(s->s_flags & MS_RDONLY))
+ mark_buffer_dirty(s->su_sbh, 1);
+ s->s_dirt = 0;
+}
+
+static struct super_operations bfs_sops = {
+ read_inode: bfs_read_inode,
+ write_inode: bfs_write_inode,
+ put_inode: NULL,
+ delete_inode: bfs_delete_inode,
+ notify_change: NULL,
+ put_super: bfs_put_super,
+ write_super: bfs_write_super,
+ statfs: bfs_statfs,
+ remount_fs: NULL,
+ clear_inode: NULL,
+ umount_begin: NULL
+};
+
+void dump_imap(const char *prefix, struct super_block * s)
+{
+#if 0
+ int i;
+ char *tmpbuf = (char *)get_free_page(GFP_KERNEL);
+
+ if (!tmpbuf)
+ return;
+ for (i=s->su_lasti; i>=0; i--) {
+ if (i>PAGE_SIZE-100) break;
+ if (test_bit(i, s->su_imap))
+ strcat(tmpbuf, "1");
+ else
+ strcat(tmpbuf, "0");
+ }
+ printk(KERN_ERR "BFS-fs: %s: lasti=%d <%s>\n", prefix, s->su_lasti, tmpbuf);
+ free_page((unsigned long)tmpbuf);
+#endif
+}
+
+static struct super_block * bfs_read_super(struct super_block * s,
+ void * data, int silent)
+{
+ kdev_t dev;
+ struct buffer_head * bh;
+ struct bfs_super_block * bfs_sb;
+ struct inode * inode;
+ int i, imap_len, bmap_len;
+
+ MOD_INC_USE_COUNT;
+ lock_super(s);
+ dev = s->s_dev;
+ set_blocksize(dev, BFS_BSIZE);
+ 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);
+ 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);
+ goto out;
+ }
+ if (BFS_UNCLEAN(bfs_sb, s) && !silent)
+ printk(KERN_WARNING "BFS-fs: %s is unclean\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);
+ 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;
+ 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;
+ }
+
+ s->su_blocks = (bfs_sb->s_end + 1)>>BFS_BSIZE_BITS; /* for statfs(2) */
+ s->su_freeb = (bfs_sb->s_end + 1 - bfs_sb->s_start)>>BFS_BSIZE_BITS;
+ s->su_freei = 0;
+ s->su_lf_eblk = 0;
+ s->su_lf_sblk = 0;
+ 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) {
+ s->su_freei++;
+ s->su_bmap[i].start = s->su_bmap[i].end = 0;
+ } else {
+ set_bit(i, s->su_imap);
+ s->su_freeb -= inode->i_blocks;
+ if (inode->iu_eblock > s->su_lf_eblk) {
+ s->su_lf_eblk = inode->iu_eblock;
+ 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);
+ }
+ if (!(s->s_flags & MS_RDONLY)) {
+ mark_buffer_dirty(bh, 1);
+ s->s_dirt = 1;
+ }
+ dump_imap("read_super", s);
+ unlock_super(s);
+ return s;
+
+out:
+ brelse(bh);
+ s->s_dev = 0;
+ unlock_super(s);
+ MOD_DEC_USE_COUNT;
+ return NULL;
+}
+
+static struct file_system_type bfs_fs_type = {
+ name: "bfs",
+ fs_flags: FS_REQUIRES_DEV,
+ read_super: bfs_read_super,
+ next: NULL
+};
+
+#ifdef MODULE
+#define init_bfs_fs init_module
+
+void cleanup_module(void)
+{
+ unregister_filesystem(&bfs_fs_type);
+}
+#endif
+
+int __init init_bfs_fs(void)
+{
+ return register_filesystem(&bfs_fs_type);
+}
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 089f83e82..1a4d09361 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -415,8 +415,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
retval = -ENOEXEC;
/* First of all, some simple consistency checks */
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0)
+ if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out;
if (elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN)
@@ -546,8 +545,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
(N_MAGIC(interp_ex) != QMAGIC))
interpreter_type = INTERPRETER_ELF;
- if (interp_elf_ex.e_ident[0] != 0x7f ||
- strncmp(&interp_elf_ex.e_ident[1], "ELF", 3) != 0)
+ if (memcmp(interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
interpreter_type &= ~INTERPRETER_ELF;
retval = -ELIBBAD;
@@ -831,8 +829,7 @@ do_load_elf_library(int fd)
if (retval != sizeof(elf_ex))
goto out_putf;
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF", 3) != 0)
+ if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
goto out_putf;
/* First of all, some simple consistency checks */
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
index aa2deaf6e..446a22623 100644
--- a/fs/binfmt_em86.c
+++ b/fs/binfmt_em86.c
@@ -30,20 +30,17 @@ static int do_load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
/* Make sure this is a Linux/Intel ELF executable... */
elf_ex = *((struct elfhdr *)bprm->buf);
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
- return -ENOEXEC;
- }
-
-
- /* First of all, some simple consistency checks */
- if ((elf_ex.e_type != ET_EXEC &&
- elf_ex.e_type != ET_DYN) ||
- (!((elf_ex.e_machine == EM_386) || (elf_ex.e_machine == EM_486))) ||
- (!bprm->dentry->d_inode->i_op || !bprm->dentry->d_inode->i_op->default_file_ops ||
- !bprm->dentry->d_inode->i_op->default_file_ops->mmap)){
- return -ENOEXEC;
- }
+ if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
+ return -ENOEXEC;
+
+ /* First of all, some simple consistency checks */
+ if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
+ (!((elf_ex.e_machine == EM_386) || (elf_ex.e_machine == EM_486))) ||
+ (!bprm->dentry->d_inode->i_op ||
+ !bprm->dentry->d_inode->i_op->default_file_ops ||
+ !bprm->dentry->d_inode->i_op->default_file_ops->mmap)) {
+ return -ENOEXEC;
+ }
bprm->sh_bang++; /* Well, the bang-shell is implicit... */
dput(bprm->dentry);
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 6143bd5d0..358890dbd 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -471,24 +471,6 @@ static int entry_proc_setup(struct binfmt_entry *e)
return 0;
}
-#ifdef MODULE
-/*
- * This is called as the fill_inode function when an inode
- * is going into (fill = 1) or out of service (fill = 0).
- * We use it here to manage the module use counts.
- *
- * Note: only the top-level directory needs to do this; if
- * a lower level is referenced, the parent will be as well.
- */
-static void bm_modcount(struct inode *inode, int fill)
-{
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
-}
-#endif
-
static int __init init_misc_binfmt(void)
{
int error = -ENOENT;
@@ -497,9 +479,7 @@ static int __init init_misc_binfmt(void)
bm_dir = create_proc_entry("sys/fs/binfmt_misc", S_IFDIR, NULL);
if (!bm_dir)
goto out;
-#ifdef MODULE
- bm_dir->fill_inode = bm_modcount;
-#endif
+ bm_dir->owner = THIS_MODULE;
status = create_proc_entry("status", S_IFREG | S_IRUGO | S_IWUSR,
bm_dir);
diff --git a/fs/buffer.c b/fs/buffer.c
index 7b2906868..0b1fd9c61 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -34,7 +34,6 @@
#include <linux/locks.h>
#include <linux/errno.h>
#include <linux/swap.h>
-#include <linux/swapctl.h>
#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/blkdev.h>
@@ -43,6 +42,7 @@
#include <linux/init.h>
#include <linux/quotaops.h>
#include <linux/iobuf.h>
+#include <linux/highmem.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -58,7 +58,7 @@ static char buffersize_index[65] =
6};
#define BUFSIZE_INDEX(X) ((int) buffersize_index[(X)>>9])
-#define MAX_BUF_PER_PAGE (PAGE_SIZE / 512)
+#define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
#define NR_RESERVED (2*MAX_BUF_PER_PAGE)
#define MAX_UNUSED_BUFFERS NR_RESERVED+20 /* don't ever have more than this
number of unused buffer heads */
@@ -91,7 +91,7 @@ struct bh_free_head {
};
static struct bh_free_head free_list[NR_SIZES];
-static kmem_cache_t *bh_cachep;
+kmem_cache_t *bh_cachep;
static int grow_buffers(int size);
@@ -130,8 +130,6 @@ union bdflush_param {
int bdflush_min[N_PARAM] = { 0, 10, 5, 25, 0, 1*HZ, 1*HZ, 1, 1};
int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,600*HZ, 6000*HZ, 6000*HZ, 2047, 5};
-void wakeup_bdflush(int);
-
/*
* Rewrote the wait-routines to use the "new" wait-queue functionality,
* and getting rid of the cli-sti pairs. The wait-queue routines still
@@ -707,7 +705,7 @@ static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
mark_buffer_uptodate(bh, uptodate);
/* This is a temporary buffer used for page I/O. */
- page = mem_map + MAP_NR(bh->b_data);
+ page = bh->b_page;
if (!uptodate)
SetPageError(page);
@@ -760,7 +758,6 @@ still_busy:
return;
}
-
/*
* Ok, this is getblk, and it isn't very clear, again to hinder
* race-conditions. Most of the code is seldom used, (ie repeating),
@@ -823,7 +820,7 @@ static int balance_dirty_state(kdev_t dev)
unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit;
dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT;
- tot = nr_lru_pages + nr_free_pages + nr_free_highpages;
+ tot = nr_free_buffer_pages();
hard_dirty_limit = tot * bdf_prm.b_un.nfract / 100;
soft_dirty_limit = hard_dirty_limit >> 1;
@@ -1092,6 +1089,20 @@ static struct buffer_head * get_unused_buffer_head(int async)
return NULL;
}
+void set_bh_page (struct buffer_head *bh, struct page *page, unsigned int offset)
+{
+ bh->b_page = page;
+ if (offset >= PAGE_SIZE)
+ BUG();
+ if (PageHighMem(page))
+ /*
+ * This catches illegal uses and preserves the offset:
+ */
+ bh->b_data = (char *)(0 + offset);
+ else
+ bh->b_data = (char *)(page_address(page) + offset);
+}
+
/*
* Create the appropriate buffers when given a page for data area and
* the size of each buffer.. Use the bh->b_this_page linked list to
@@ -1101,7 +1112,7 @@ static struct buffer_head * get_unused_buffer_head(int async)
* from ordinary buffer allocations, and only async requests are allowed
* to sleep waiting for buffer heads.
*/
-static struct buffer_head * create_buffers(unsigned long page, unsigned long size, int async)
+static struct buffer_head * create_buffers(struct page * page, unsigned long size, int async)
{
struct buffer_head *bh, *head;
long offset;
@@ -1124,7 +1135,8 @@ try_again:
atomic_set(&bh->b_count, 0);
bh->b_size = size;
- bh->b_data = (char *) (page+offset);
+ set_bh_page(bh, page, offset);
+
bh->b_list = BUF_CLEAN;
bh->b_end_io = end_buffer_io_bad;
}
@@ -1183,7 +1195,7 @@ static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], i
* They don't show up in the buffer hash table, but they *are*
* registered in page->buffers.
*/
- head = create_buffers(page_address(page), size, 1);
+ head = create_buffers(page, size, 1);
if (page->buffers)
BUG();
if (!head)
@@ -1273,7 +1285,7 @@ static void create_empty_buffers(struct page *page, struct inode *inode, unsigne
{
struct buffer_head *bh, *head, *tail;
- head = create_buffers(page_address(page), blocksize, 1);
+ head = create_buffers(page, blocksize, 1);
if (page->buffers)
BUG();
@@ -1293,13 +1305,17 @@ static void create_empty_buffers(struct page *page, struct inode *inode, unsigne
static void unmap_underlying_metadata(struct buffer_head * bh)
{
#if 0
- bh = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
- if (bh) {
- unmap_buffer(bh);
- /* Here we could run brelse or bforget. We use
- bforget because it will try to put the buffer
- in the freelist. */
- __bforget(bh);
+ 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);
+ }
}
#endif
}
@@ -1313,7 +1329,7 @@ int block_write_full_page(struct file *file, struct page *page)
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
int err, i;
- unsigned long block, offset;
+ unsigned long block;
struct buffer_head *bh, *head;
if (!PageLocked(page))
@@ -1323,12 +1339,10 @@ int block_write_full_page(struct file *file, struct page *page)
create_empty_buffers(page, inode, inode->i_sb->s_blocksize);
head = page->buffers;
- offset = page->offset;
- block = offset >> inode->i_sb->s_blocksize_bits;
-
- // FIXME: currently we assume page alignment.
- if (offset & (PAGE_SIZE-1))
- BUG();
+ /* 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;
@@ -1375,10 +1389,11 @@ int block_write_partial_page(struct file *file, struct page *page, unsigned long
unsigned long start_offset, start_bytes, end_bytes;
unsigned long bbits, blocks, i, len;
struct buffer_head *bh, *head;
- char * target_buf;
+ char *target_buf, *kaddr;
int need_balance_dirty;
- target_buf = (char *)page_address(page) + offset;
+ kaddr = (char *)kmap(page);
+ target_buf = kaddr + offset;
if (!PageLocked(page))
BUG();
@@ -1389,8 +1404,8 @@ int block_write_partial_page(struct file *file, struct page *page, unsigned long
head = page->buffers;
bbits = inode->i_sb->s_blocksize_bits;
- block = page->offset >> bbits;
- blocks = PAGE_SIZE >> bbits;
+ block = page->index << (PAGE_CACHE_SHIFT - bbits);
+ blocks = PAGE_CACHE_SIZE >> bbits;
start_block = offset >> bbits;
end_block = (offset + bytes - 1) >> bbits;
start_offset = offset & (blocksize - 1);
@@ -1409,9 +1424,6 @@ int block_write_partial_page(struct file *file, struct page *page, unsigned long
BUG();
if (end_block < 0 || end_block >= blocks)
BUG();
- // FIXME: currently we assume page alignment.
- if (page->offset & (PAGE_SIZE-1))
- BUG();
i = 0;
bh = head;
@@ -1446,7 +1458,7 @@ int block_write_partial_page(struct file *file, struct page *page, unsigned long
if (!buffer_uptodate(bh) && (start_offset || (end_bytes && (i == end_block)))) {
if (buffer_new(bh)) {
- memset(bh->b_data, 0, bh->b_size);
+ memset(kaddr + i*blocksize, 0, blocksize);
} else {
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
@@ -1464,6 +1476,10 @@ int block_write_partial_page(struct file *file, struct page *page, unsigned long
len = end_bytes;
end_bytes = 0;
}
+ if (target_buf >= kaddr + PAGE_SIZE)
+ BUG();
+ if (target_buf+len-1 >= kaddr + PAGE_SIZE)
+ BUG();
err = copy_from_user(target_buf, buf, len);
target_buf += len;
buf += len;
@@ -1512,9 +1528,11 @@ skip:
*/
if (!partial)
SetPageUptodate(page);
+ kunmap(page);
return bytes;
out:
ClearPageUptodate(page);
+ kunmap(page);
return err;
}
@@ -1537,12 +1555,12 @@ int block_write_cont_page(struct file *file, struct page *page, unsigned long of
unsigned long data_offset = offset;
int need_balance_dirty;
- offset = inode->i_size - page->offset;
- if (page->offset>inode->i_size)
+ offset = inode->i_size - (page->index << PAGE_CACHE_SHIFT);
+ if (page->index > (inode->i_size >> PAGE_CACHE_SHIFT))
offset = 0;
else if (offset >= data_offset)
offset = data_offset;
- bytes += data_offset-offset;
+ bytes += data_offset - offset;
target_buf = (char *)page_address(page) + offset;
target_data = (char *)page_address(page) + data_offset;
@@ -1556,8 +1574,8 @@ int block_write_cont_page(struct file *file, struct page *page, unsigned long of
head = page->buffers;
bbits = inode->i_sb->s_blocksize_bits;
- block = page->offset >> bbits;
- blocks = PAGE_SIZE >> bbits;
+ block = page->index << (PAGE_CACHE_SHIFT - bbits);
+ blocks = PAGE_CACHE_SIZE >> bbits;
start_block = offset >> bbits;
end_block = (offset + bytes - 1) >> bbits;
start_offset = offset & (blocksize - 1);
@@ -1576,9 +1594,6 @@ int block_write_cont_page(struct file *file, struct page *page, unsigned long of
BUG();
if (end_block < 0 || end_block >= blocks)
BUG();
- // FIXME: currently we assume page alignment.
- if (page->offset & (PAGE_SIZE-1))
- BUG();
i = 0;
bh = head;
@@ -1718,8 +1733,6 @@ static void end_buffer_io_kiobuf(struct buffer_head *bh, int uptodate)
* for them to complete. Clean up the buffer_heads afterwards.
*/
-#define dprintk(x...)
-
static int do_kio(struct kiobuf *kiobuf,
int rw, int nr, struct buffer_head *bh[], int size)
{
@@ -1730,8 +1743,6 @@ static int do_kio(struct kiobuf *kiobuf,
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- dprintk ("do_kio start %d\n", rw);
-
if (rw == WRITE)
rw = WRITERAW;
atomic_add(nr, &kiobuf->io_count);
@@ -1757,8 +1768,6 @@ static int do_kio(struct kiobuf *kiobuf,
spin_unlock(&unused_list_lock);
- dprintk ("do_kio end %d %d\n", iosize, err);
-
if (iosize)
return iosize;
if (kiobuf->errno)
@@ -1812,12 +1821,6 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
panic("brw_kiovec: iobuf not initialised");
}
- /* DEBUG */
-#if 0
- return iobuf->length;
-#endif
- dprintk ("brw_kiovec: start\n");
-
/*
* OK to walk down the iovec doing page IO on each page we find.
*/
@@ -1826,7 +1829,6 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
iobuf = iovec[i];
offset = iobuf->offset;
length = iobuf->length;
- dprintk ("iobuf %d %d %d\n", offset, length, size);
for (pageind = 0; pageind < iobuf->nr_pages; pageind++) {
map = iobuf->maplist[pageind];
@@ -1846,7 +1848,7 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
tmp->b_dev = B_FREE;
tmp->b_size = size;
- tmp->b_data = (char *) (page + offset);
+ set_bh_page(tmp, map, offset);
tmp->b_this_page = tmp;
init_buffer(tmp, end_buffer_io_kiobuf, NULL);
@@ -1860,8 +1862,6 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
set_bit(BH_Dirty, &tmp->b_state);
}
- dprintk ("buffer %d (%d) at %p\n",
- bhind, tmp->b_blocknr, tmp->b_data);
bh[bhind++] = tmp;
length -= size;
offset += size;
@@ -1896,7 +1896,6 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
}
finished:
- dprintk ("brw_kiovec: end (%d, %d)\n", transferred, err);
if (transferred)
return transferred;
return err;
@@ -2006,7 +2005,8 @@ int block_read_full_page(struct file * file, struct page * page)
unsigned long iblock;
struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
unsigned int blocksize, blocks;
- int nr;
+ unsigned long kaddr = 0;
+ int nr, i;
if (!PageLocked(page))
PAGE_BUG(page);
@@ -2015,10 +2015,11 @@ int block_read_full_page(struct file * file, struct page * page)
create_empty_buffers(page, inode, blocksize);
head = page->buffers;
- blocks = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
- iblock = page->offset >> inode->i_sb->s_blocksize_bits;
+ 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))
@@ -2027,7 +2028,9 @@ int block_read_full_page(struct file * file, struct page * page)
if (!buffer_mapped(bh)) {
inode->i_op->get_block(inode, iblock, bh, 0);
if (!buffer_mapped(bh)) {
- memset(bh->b_data, 0, blocksize);
+ if (!kaddr)
+ kaddr = kmap(page);
+ memset((char *)(kaddr + i*blocksize), 0, blocksize);
set_bit(BH_Uptodate, &bh->b_state);
continue;
}
@@ -2037,7 +2040,7 @@ int block_read_full_page(struct file * file, struct page * page)
atomic_inc(&bh->b_count);
arr[nr] = bh;
nr++;
- } while (iblock++, (bh = bh->b_this_page) != head);
+ } while (i++, iblock++, (bh = bh->b_this_page) != head);
++current->maj_flt;
if (nr) {
@@ -2052,6 +2055,8 @@ int block_read_full_page(struct file * file, struct page * page)
SetPageUptodate(page);
UnlockPage(page);
}
+ if (kaddr)
+ kunmap(page);
return 0;
}
@@ -2061,8 +2066,7 @@ int block_read_full_page(struct file * file, struct page * page)
*/
static int grow_buffers(int size)
{
- unsigned long page;
- struct page * page_map;
+ struct page * page;
struct buffer_head *bh, *tmp;
struct buffer_head * insert_point;
int isize;
@@ -2072,8 +2076,9 @@ static int grow_buffers(int size)
return 0;
}
- if (!(page = __get_free_page(GFP_BUFFER)))
- return 0;
+ page = alloc_page(GFP_BUFFER);
+ if (!page)
+ goto out;
bh = create_buffers(page, size, 0);
if (!bh)
goto no_buffer_head;
@@ -2103,14 +2108,14 @@ static int grow_buffers(int size)
free_list[isize].list = bh;
spin_unlock(&free_list[isize].lock);
- page_map = mem_map + MAP_NR(page);
- page_map->buffers = bh;
- lru_cache_add(page_map);
+ page->buffers = bh;
+ lru_cache_add(page);
atomic_inc(&buffermem_pages);
return 1;
no_buffer_head:
- free_page(page);
+ __free_page(page);
+out:
return 0;
}
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 378c4f7a6..d5cf1afef 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -99,7 +99,7 @@ static int coda_readpage(struct file * coda_file, struct page * page)
&cont_file, &cont_dentry);
CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n",
- coda_inode->i_ino, cii->c_ovp->i_ino, page->offset);
+ coda_inode->i_ino, cii->c_ovp->i_ino, page->index);
block_read_full_page(&cont_file, page);
EXIT;
diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c
index e35174e5c..42b0fafca 100644
--- a/fs/coda/sysctl.c
+++ b/fs/coda/sysctl.c
@@ -476,55 +476,12 @@ int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
*/
-struct proc_dir_entry proc_fs_coda = {
- PROC_FS_CODA, 4, "coda",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL,
- NULL, NULL
-};
-
-struct proc_dir_entry proc_coda_vfs = {
- PROC_VFS_STATS , 9, "vfs_stats",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- coda_vfs_stats_get_info
- };
-
-struct proc_dir_entry proc_coda_upcall = {
- PROC_UPCALL_STATS , 12, "upcall_stats",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- coda_upcall_stats_get_info
- };
-
-struct proc_dir_entry proc_coda_permission = {
- PROC_PERMISSION_STATS , 16, "permission_stats",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- coda_permission_stats_get_info
- };
-
-
-struct proc_dir_entry proc_coda_cache_inv = {
- PROC_CACHE_INV_STATS , 15, "cache_inv_stats",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- coda_cache_inv_stats_get_info
- };
-
-static void coda_proc_modcount(struct inode *inode, int fill)
-{
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
-
-}
+struct proc_dir_entry* proc_fs_coda;
#endif
+#define coda_proc_create(name,get_info) \
+ create_proc_info_entry(name, 0, proc_fs_coda, get_info)
void coda_sysctl_init()
{
@@ -535,12 +492,12 @@ void coda_sysctl_init()
reset_coda_cache_inv_stats();
#ifdef CONFIG_PROC_FS
- proc_register(&proc_root_fs,&proc_fs_coda);
- proc_fs_coda.fill_inode = &coda_proc_modcount;
- proc_register(&proc_fs_coda,&proc_coda_vfs);
- proc_register(&proc_fs_coda,&proc_coda_upcall);
- proc_register(&proc_fs_coda,&proc_coda_permission);
- proc_register(&proc_fs_coda,&proc_coda_cache_inv);
+ proc_fs_coda = create_proc_entry("coda", S_IFDIR, proc_root_fs);
+ proc_fs_coda->owner = THIS_MODULE;
+ coda_proc_create("vfs_stats", coda_vfs_stats_get_info);
+ coda_proc_create("upcall_stats", coda_upcall_stats_get_info);
+ coda_proc_create("permission_stats", coda_permission_stats_get_info);
+ coda_proc_create("cache_inv_stats", coda_cache_inv_stats_get_info);
#endif
#ifdef CONFIG_SYSCTL
@@ -560,10 +517,10 @@ void coda_sysctl_clean()
#endif
#if CONFIG_PROC_FS
- proc_unregister(&proc_fs_coda, proc_coda_cache_inv.low_ino);
- proc_unregister(&proc_fs_coda, proc_coda_permission.low_ino);
- proc_unregister(&proc_fs_coda, proc_coda_upcall.low_ino);
- proc_unregister(&proc_fs_coda, proc_coda_vfs.low_ino);
- proc_unregister(&proc_root_fs, proc_fs_coda.low_ino);
+ remove_proc_entry("cache_inv_stats", proc_fs_coda);
+ remove_proc_entry("permission_stats", proc_fs_coda);
+ remove_proc_entry("upcall_stats", proc_fs_coda);
+ remove_proc_entry("vfs_stats", proc_fs_coda);
+ remove_proc_entry("coda", proc_root_fs);
#endif
}
diff --git a/fs/dcache.c b/fs/dcache.c
index b6f7a7203..f96f8cf7f 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -214,7 +214,8 @@ static inline void prune_one_dentry(struct dentry * dentry)
dentry_iput(dentry);
parent = dentry->d_parent;
d_free(dentry);
- dput(parent);
+ if (parent != dentry)
+ dput(parent);
}
/*
@@ -712,7 +713,7 @@ char * d_path(struct dentry *dentry, char *buffer, int buflen)
*--end = '\0';
buflen--;
- if (dentry->d_parent != dentry && list_empty(&dentry->d_hash)) {
+ if (!IS_ROOT(dentry) && list_empty(&dentry->d_hash)) {
buflen -= 10;
end -= 10;
memcpy(end, " (deleted)", 10);
diff --git a/fs/exec.c b/fs/exec.c
index dea4f0712..a7ca3dfaa 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -225,17 +225,13 @@ int copy_strings(int argc,char ** argv, struct linux_binprm *bprm)
page = bprm->page[i];
new = 0;
if (!page) {
- /*
- * Cannot yet use highmem page because
- * we cannot sleep with a kmap held.
- */
- page = __get_pages(GFP_USER, 0);
+ page = alloc_page(GFP_HIGHUSER);
bprm->page[i] = page;
if (!page)
return -ENOMEM;
new = 1;
}
- kaddr = (char *)kmap(page, KM_WRITE);
+ kaddr = (char *)kmap(page);
if (new && offset)
memset(kaddr, 0, offset);
@@ -247,7 +243,7 @@ int copy_strings(int argc,char ** argv, struct linux_binprm *bprm)
}
err = copy_from_user(kaddr + offset, str, bytes_to_copy);
flush_page_to_ram(page);
- kunmap((unsigned long)kaddr, KM_WRITE);
+ kunmap(page);
if (err)
return -EFAULT;
@@ -297,7 +293,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
mpnt->vm_page_prot = PAGE_COPY;
mpnt->vm_flags = VM_STACK_FLAGS;
mpnt->vm_ops = NULL;
- mpnt->vm_offset = 0;
+ mpnt->vm_pgoff = 0;
mpnt->vm_file = NULL;
mpnt->vm_private_data = (void *) 0;
vmlist_modify_lock(current->mm);
@@ -462,6 +458,7 @@ int flush_old_exec(struct linux_binprm * bprm)
/*
* Make sure we have a private signal table
*/
+ task_lock(current);
oldsig = current->sig;
retval = make_private_signals();
if (retval) goto flush_failed;
@@ -500,6 +497,7 @@ int flush_old_exec(struct linux_binprm * bprm)
flush_signal_handlers(current);
flush_old_files(current->files);
+ task_unlock(current);
return 0;
@@ -508,6 +506,7 @@ mmap_failed:
kfree(current->sig);
flush_failed:
current->sig = oldsig;
+ task_unlock(current);
return retval;
}
@@ -681,12 +680,12 @@ void remove_arg_zero(struct linux_binprm *bprm)
if (offset != PAGE_SIZE)
continue;
offset = 0;
- kunmap((unsigned long)kaddr, KM_WRITE);
+ kunmap(page);
inside:
page = bprm->page[bprm->p/PAGE_SIZE];
- kaddr = (char *)kmap(page, KM_WRITE);
+ kaddr = (char *)kmap(page);
}
- kunmap((unsigned long)kaddr, KM_WRITE);
+ kunmap(page);
bprm->argc--;
}
}
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index 111a2d6e0..5ec306fdf 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -7,16 +7,16 @@
* Universite Pierre et Marie Curie (Paris VI)
*/
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+
+
/*
* This file will contain the Access Control Lists management for the
* second extended file system.
*/
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
/*
* ext2_permission ()
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index b7cfd2212..e0f7a655c 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -11,6 +11,12 @@
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
+
+
/*
* balloc.c contains the blocks allocation and deallocation routines
*/
@@ -26,16 +32,6 @@
* when a file system is mounted (see ext2_read_super).
*/
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/stat.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/locks.h>
-#include <linux/quotaops.h>
-
-#include <asm/bitops.h>
-#include <asm/byteorder.h>
#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
diff --git a/fs/ext2/bitmap.c b/fs/ext2/bitmap.c
index 8b9b5d233..ddd0ac12c 100644
--- a/fs/ext2/bitmap.c
+++ b/fs/ext2/bitmap.c
@@ -7,8 +7,10 @@
* Universite Pierre et Marie Curie (Paris VI)
*/
+#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+
+
static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index cf9e615bd..e1f45105e 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -18,13 +18,10 @@
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
-#include <asm/uaccess.h>
-
-#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
+
+
static ssize_t ext2_dir_read (struct file * filp, char * buf,
size_t count, loff_t *ppos)
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index e223ce277..987b55f94 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -18,19 +18,11 @@
* (jj@sunsite.ms.mff.cuni.cz)
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/fcntl.h>
#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/locks.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
+
+
#define NBUF 32
@@ -40,8 +32,7 @@
static long long ext2_file_lseek(struct file *, long long, int);
#if BITS_PER_LONG < 64
static int ext2_open_file (struct inode *, struct file *);
-
-#else
+#endif
#define EXT2_MAX_SIZE(bits) \
(((EXT2_NDIR_BLOCKS + (1LL << (bits - 2)) + \
@@ -54,9 +45,6 @@ static long long ext2_max_sizes[] = {
EXT2_MAX_SIZE(10), EXT2_MAX_SIZE(11), EXT2_MAX_SIZE(12), EXT2_MAX_SIZE(13)
};
-#endif
-
-
/*
* Make sure the offset never goes beyond the 32-bit mark..
*/
@@ -74,13 +62,11 @@ static long long ext2_file_lseek(
case 1:
offset += file->f_pos;
}
- if (((unsigned long long) offset >> 32) != 0) {
-#if BITS_PER_LONG < 64
+ if (offset<0)
return -EINVAL;
-#else
+ if (((unsigned long long) offset >> 32) != 0) {
if (offset > ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(inode->i_sb)])
return -EINVAL;
-#endif
}
if (offset != file->f_pos) {
file->f_pos = offset;
@@ -139,11 +125,12 @@ static int ext2_release_file (struct inode * inode, struct file * filp)
#if BITS_PER_LONG < 64
/*
* Called when an inode is about to be open.
- * We use this to disallow opening RW large files on 32bit systems.
+ * We use this to disallow opening RW large files on 32bit systems if
+ * the caller didn't specify O_LARGEFILE.
*/
static int ext2_open_file (struct inode * inode, struct file * filp)
{
- if (inode->u.ext2_i.i_high_size && (filp->f_mode & FMODE_WRITE))
+ if (inode->u.ext2_i.i_high_size && !(filp->f_flags & O_LARGEFILE))
return -EFBIG;
return 0;
}
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index 3969e17e9..cd12a68bd 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -22,17 +22,10 @@
* we can depend on generic_block_fdatasync() to sync the data blocks.
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/byteorder.h>
-
-#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/locks.h>
+
+
#define blocksize (EXT2_BLOCK_SIZE(inode->i_sb))
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index d4b5ca33f..d6953e4cb 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -12,6 +12,12 @@
* David S. Miller (davem@caip.rutgers.edu), 1995
*/
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
+
+
/*
* ialloc.c contains the inodes allocation and deallocation routines
*/
@@ -27,16 +33,6 @@
* when a file system is mounted (see ext2_read_super).
*/
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/locks.h>
-#include <linux/quotaops.h>
-
-#include <asm/bitops.h>
-#include <asm/byteorder.h>
/*
* Read the inode allocation bitmap for a given block_group, reading
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 4cf932d51..a980df858 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -20,18 +20,13 @@
* (jj@sunsite.ms.mff.cuni.cz)
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/string.h>
#include <linux/locks.h>
-#include <linux/mm.h>
#include <linux/smp_lock.h>
+#include <linux/sched.h>
+
+
static int ext2_update_inode(struct inode * inode, int do_sync);
@@ -692,15 +687,8 @@ void ext2_read_inode (struct inode * inode)
inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
else {
inode->u.ext2_i.i_dir_acl = 0;
- inode->u.ext2_i.i_high_size =
- le32_to_cpu(raw_inode->i_size_high);
-#if BITS_PER_LONG < 64
- if (raw_inode->i_size_high)
- inode->i_size = (__u32)-1;
-#else
- inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high))
- << 32;
-#endif
+ inode->u.ext2_i.i_high_size = le32_to_cpu(raw_inode->i_size_high);
+ inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
}
inode->i_generation = le32_to_cpu(raw_inode->i_generation);
inode->u.ext2_i.i_block_group = block_group;
@@ -821,14 +809,9 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
raw_inode->i_file_acl = cpu_to_le32(inode->u.ext2_i.i_file_acl);
if (S_ISDIR(inode->i_mode))
raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl);
- else {
-#if BITS_PER_LONG < 64
- raw_inode->i_size_high =
- cpu_to_le32(inode->u.ext2_i.i_high_size);
-#else
+ else
raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32);
-#endif
- }
+
raw_inode->i_generation = cpu_to_le32(inode->i_generation);
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index 4d54fd354..a582fd545 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -7,14 +7,11 @@
* Universite Pierre et Marie Curie (Paris VI)
*/
-#include <asm/uaccess.h>
-
-#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/ioctl.h>
#include <linux/sched.h>
-#include <linux/mm.h>
+#include <asm/uaccess.h>
+
int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
unsigned long arg)
@@ -26,7 +23,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
switch (cmd) {
case EXT2_IOC_GETFLAGS:
flags = inode->u.ext2_i.i_flags & EXT2_FL_USER_VISIBLE;
- return put_user(inode->u.ext2_i.i_flags, (int *) arg);
+ return put_user(flags, (int *) arg);
case EXT2_IOC_SETFLAGS: {
unsigned int oldflags;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 90cb80050..8bc7532de 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -18,19 +18,13 @@
* for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
*/
-#include <asm/uaccess.h>
-
-#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/string.h>
#include <linux/locks.h>
#include <linux/quotaops.h>
+
/*
* define how far ahead to read directories while searching them.
*/
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 37b8e15c5..dadd3c67e 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -17,23 +17,14 @@
*/
#include <linux/module.h>
-
-#include <stdarg.h>
-
-#include <asm/bitops.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/malloc.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
#include <linux/string.h>
-#include <linux/locks.h>
-#include <linux/blkdev.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/locks.h>
+#include <asm/uaccess.h>
+
+
static char error_buf[1024];
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index 5f73159c3..bf880e68a 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -15,14 +15,11 @@
* ext2 symlink handling code
*/
+#include <linux/module.h>
+#include <linux/fs.h>
#include <asm/uaccess.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/stat.h>
+
static int ext2_readlink (struct dentry *, char *, int);
static struct dentry *ext2_follow_link(struct dentry *, struct dentry *, unsigned int);
diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c
index d824edb0b..653936278 100644
--- a/fs/ext2/truncate.c
+++ b/fs/ext2/truncate.c
@@ -18,20 +18,16 @@
* General cleanup and race fixes, wsh, 1998
*/
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/locks.h>
+
+
/*
* Real random numbers for secure rm added 94/02/18
* Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
*/
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/locks.h>
-#include <linux/string.h>
-
#if 0
/*
@@ -54,8 +50,7 @@ static int ext2_secrm_seed = 152; /* Random generator base */
* there's no need to test for changes during the operation.
*/
#define DIRECT_BLOCK(inode) \
- ((inode->i_size + inode->i_sb->s_blocksize - 1) / \
- inode->i_sb->s_blocksize)
+ ((unsigned long) ((inode->i_size + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits))
#define INDIRECT_BLOCK(inode,offset) ((int)DIRECT_BLOCK(inode) - offset)
#define DINDIRECT_BLOCK(inode,offset) \
(INDIRECT_BLOCK(inode,offset) / addr_per_block)
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 505dc4e06..9c2c159cb 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -118,8 +118,8 @@ static int fat_write_partial_page(struct file *file, struct page *page, unsigned
struct page *page_cache = NULL;
long status;
- pgpos = MSDOS_I(inode)->i_realsize & PAGE_CACHE_MASK;
- while (pgpos < page->offset) {
+ pgpos = MSDOS_I(inode)->i_realsize >> PAGE_CACHE_SHIFT;
+ while (pgpos < page->index) {
hash = page_hash(&inode->i_data, pgpos);
repeat_find: new_page = __find_lock_page(&inode->i_data, pgpos, hash);
if (!new_page) {
@@ -140,7 +140,7 @@ repeat_find: new_page = __find_lock_page(&inode->i_data, pgpos, hash);
page_cache_release(new_page);
if (status < 0)
goto out;
- pgpos = MSDOS_I(inode)->i_realsize & PAGE_CACHE_MASK;
+ pgpos = MSDOS_I(inode)->i_realsize >> PAGE_CACHE_SHIFT;
}
status = block_write_cont_page(file, page, offset, bytes, buf);
out:
@@ -182,6 +182,7 @@ ssize_t default_fat_file_write(
void fat_truncate(struct inode *inode)
{
+ struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
int cluster;
/* Why no return value? Surely the disk could fail... */
@@ -189,9 +190,9 @@ void fat_truncate(struct inode *inode)
return /* -EPERM */;
if (IS_IMMUTABLE(inode))
return /* -EPERM */;
- cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
+ cluster = SECTOR_SIZE*sbi->cluster_size;
MSDOS_I(inode)->i_realsize = ((inode->i_size-1) | (SECTOR_SIZE-1)) + 1;
- (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
+ 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;
mark_inode_dirty(inode);
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 4262fa756..033c40c2b 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -364,21 +364,22 @@ out:
static void fat_read_root(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
int nr;
INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
MSDOS_I(inode)->i_location = 0;
MSDOS_I(inode)->i_fat_inode = inode;
- inode->i_uid = MSDOS_SB(sb)->options.fs_uid;
- inode->i_gid = MSDOS_SB(sb)->options.fs_gid;
+ inode->i_uid = sbi->options.fs_uid;
+ inode->i_gid = sbi->options.fs_gid;
inode->i_version = ++event;
- inode->i_mode = (S_IRWXUGO & ~MSDOS_SB(sb)->options.fs_umask) | S_IFDIR;
- inode->i_op = MSDOS_SB(sb)->dir_ops;
- if (MSDOS_SB(sb)->fat_bits == 32) {
- MSDOS_I(inode)->i_start = MSDOS_SB(sb)->root_cluster;
+ inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_umask) | S_IFDIR;
+ inode->i_op = sbi->dir_ops;
+ if (sbi->fat_bits == 32) {
+ MSDOS_I(inode)->i_start = sbi->root_cluster;
if ((nr = MSDOS_I(inode)->i_start) != 0) {
while (nr != -1) {
- inode->i_size += SECTOR_SIZE*MSDOS_SB(sb)->cluster_size;
+ inode->i_size += SECTOR_SIZE*sbi->cluster_size;
if (!(nr = fat_access(sb,nr,-1))) {
printk("Directory %ld: bad FAT\n",
inode->i_ino);
@@ -388,12 +389,13 @@ static void fat_read_root(struct inode *inode)
}
} else {
MSDOS_I(inode)->i_start = 0;
- inode->i_size = MSDOS_SB(sb)->dir_entries*
+ inode->i_size = sbi->dir_entries*
sizeof(struct msdos_dir_entry);
}
- inode->i_blksize = MSDOS_SB(sb)->cluster_size* SECTOR_SIZE;
- inode->i_blocks = (inode->i_size+inode->i_blksize-1)/
- inode->i_blksize*MSDOS_SB(sb)->cluster_size;
+ inode->i_blksize = sbi->cluster_size* SECTOR_SIZE;
+ inode->i_blocks =
+ ((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;
@@ -429,6 +431,7 @@ fat_read_super(struct super_block *sb, void *data, int silent,
struct inode *root_inode;
struct buffer_head *bh;
struct fat_boot_sector *b;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
char *p;
int data_sectors,logical_sector_size,sector_mult,fat_clusters=0;
int debug,error,fat,cp;
@@ -442,12 +445,12 @@ fat_read_super(struct super_block *sb, void *data, int silent,
cvf_format[0] = '\0';
cvf_options[0] = '\0';
- MSDOS_SB(sb)->cvf_format = NULL;
- MSDOS_SB(sb)->private_data = NULL;
+ sbi->cvf_format = NULL;
+ sbi->private_data = NULL;
MOD_INC_USE_COUNT;
- MSDOS_SB(sb)->dir_ops = fs_dir_inode_ops;
- MSDOS_SB(sb)->put_super_callback = NULL;
+ sbi->dir_ops = fs_dir_inode_ops;
+ sbi->put_super_callback = NULL;
sb->s_op = &fat_sops;
if (hardsect_size[MAJOR(sb->s_dev)] != NULL){
blksize = hardsect_size[MAJOR(sb->s_dev)][MINOR(sb->s_dev)];
@@ -457,13 +460,13 @@ fat_read_super(struct super_block *sb, void *data, int silent,
}
- opts.isvfat = MSDOS_SB(sb)->options.isvfat;
+ opts.isvfat = sbi->options.isvfat;
if (!parse_options((char *) data, &fat, &blksize, &debug, &opts,
cvf_format, cvf_options)
|| (blksize != 512 && blksize != 1024 && blksize != 2048))
goto out_fail;
/* N.B. we should parse directly into the sb structure */
- memcpy(&(MSDOS_SB(sb)->options), &opts, sizeof(struct fat_mount_options));
+ memcpy(&(sbi->options), &opts, sizeof(struct fat_mount_options));
fat_cache_init();
lock_super(sb);
@@ -508,69 +511,79 @@ fat_read_super(struct super_block *sb, void *data, int silent,
logical_sector_size =
CF_LE_W(get_unaligned((unsigned short *) &b->sector_size));
sector_mult = logical_sector_size >> SECTOR_BITS;
- MSDOS_SB(sb)->cluster_size = b->cluster_size*sector_mult;
- MSDOS_SB(sb)->fats = b->fats;
- MSDOS_SB(sb)->fat_start = CF_LE_W(b->reserved)*sector_mult;
+ sbi->cluster_size = b->cluster_size*sector_mult;
+ if (!sbi->cluster_size || (sbi->cluster_size & (sbi->cluster_size-1))) {
+ printk("fatfs: bogus cluster size\n");
+ brelse(bh);
+ goto out_invalid;
+ }
+ for (sbi->cluster_bits=0;
+ 1<<sbi->cluster_bits<sbi->cluster_size;
+ sbi->cluster_bits++)
+ ;
+ sbi->cluster_bits += SECTOR_BITS;
+ sbi->fats = b->fats;
+ sbi->fat_start = CF_LE_W(b->reserved)*sector_mult;
if (!b->fat_length && b->fat32_length) {
struct fat_boot_fsinfo *fsinfo;
/* Must be FAT32 */
fat32 = 1;
- MSDOS_SB(sb)->fat_length= CF_LE_L(b->fat32_length)*sector_mult;
- MSDOS_SB(sb)->root_cluster = CF_LE_L(b->root_cluster);
+ sbi->fat_length= CF_LE_L(b->fat32_length)*sector_mult;
+ sbi->root_cluster = CF_LE_L(b->root_cluster);
/* MC - if info_sector is 0, don't multiply by 0 */
if(CF_LE_W(b->info_sector) == 0) {
- MSDOS_SB(sb)->fsinfo_offset =
+ sbi->fsinfo_offset =
logical_sector_size + 0x1e0;
} else {
- MSDOS_SB(sb)->fsinfo_offset =
+ sbi->fsinfo_offset =
(CF_LE_W(b->info_sector) * logical_sector_size)
+ 0x1e0;
}
- if (MSDOS_SB(sb)->fsinfo_offset + sizeof(struct fat_boot_fsinfo) > sb->s_blocksize) {
+ if (sbi->fsinfo_offset + sizeof(struct fat_boot_fsinfo) > sb->s_blocksize) {
printk("fat_read_super: Bad fsinfo_offset\n");
- fat_brelse(sb, bh);
+ brelse(bh);
goto out_invalid;
}
fsinfo = (struct fat_boot_fsinfo *)
- &bh->b_data[MSDOS_SB(sb)->fsinfo_offset];
+ &bh->b_data[sbi->fsinfo_offset];
if (CF_LE_L(fsinfo->signature) != 0x61417272) {
printk("fat_read_super: Did not find valid FSINFO "
"signature. Found 0x%x\n",
CF_LE_L(fsinfo->signature));
} else {
- MSDOS_SB(sb)->free_clusters = CF_LE_L(fsinfo->free_clusters);
+ sbi->free_clusters = CF_LE_L(fsinfo->free_clusters);
}
} else {
fat32 = 0;
- MSDOS_SB(sb)->fat_length = CF_LE_W(b->fat_length)*sector_mult;
- MSDOS_SB(sb)->root_cluster = 0;
- MSDOS_SB(sb)->free_clusters = -1; /* Don't know yet */
+ sbi->fat_length = CF_LE_W(b->fat_length)*sector_mult;
+ sbi->root_cluster = 0;
+ sbi->free_clusters = -1; /* Don't know yet */
}
- MSDOS_SB(sb)->dir_start= CF_LE_W(b->reserved)*sector_mult+
- b->fats*MSDOS_SB(sb)->fat_length;
- MSDOS_SB(sb)->dir_entries =
+ sbi->dir_start= CF_LE_W(b->reserved)*sector_mult+
+ b->fats*sbi->fat_length;
+ sbi->dir_entries =
CF_LE_W(get_unaligned((unsigned short *) &b->dir_entries));
- MSDOS_SB(sb)->data_start = MSDOS_SB(sb)->dir_start+ROUND_TO_MULTIPLE((
- MSDOS_SB(sb)->dir_entries << MSDOS_DIR_BITS) >> SECTOR_BITS,
+ sbi->data_start = sbi->dir_start+ROUND_TO_MULTIPLE((
+ sbi->dir_entries << MSDOS_DIR_BITS) >> SECTOR_BITS,
sector_mult);
data_sectors = CF_LE_W(get_unaligned((unsigned short *) &b->sectors));
if (!data_sectors) {
data_sectors = CF_LE_L(b->total_sect);
}
- data_sectors = data_sectors * sector_mult - MSDOS_SB(sb)->data_start;
+ data_sectors = data_sectors * sector_mult - sbi->data_start;
error = !b->cluster_size || !sector_mult;
if (!error) {
- MSDOS_SB(sb)->clusters = b->cluster_size ? data_sectors/
+ sbi->clusters = b->cluster_size ? data_sectors/
b->cluster_size/sector_mult : 0;
- MSDOS_SB(sb)->fat_bits = fat32 ? 32 :
+ sbi->fat_bits = fat32 ? 32 :
(fat ? fat :
- (MSDOS_SB(sb)->clusters > MSDOS_FAT12 ? 16 : 12));
- fat_clusters = MSDOS_SB(sb)->fat_length*SECTOR_SIZE*8/
- MSDOS_SB(sb)->fat_bits;
- error = !MSDOS_SB(sb)->fats || (MSDOS_SB(sb)->dir_entries &
- (MSDOS_DPS-1)) || MSDOS_SB(sb)->clusters+2 > fat_clusters+
+ (sbi->clusters > MSDOS_FAT12 ? 16 : 12));
+ fat_clusters = sbi->fat_length*SECTOR_SIZE*8/
+ sbi->fat_bits;
+ error = !sbi->fats || (sbi->dir_entries &
+ (MSDOS_DPS-1)) || sbi->clusters+2 > fat_clusters+
MSDOS_MAX_EXTRA || (logical_sector_size & (SECTOR_SIZE-1))
|| !b->secs_track || !b->heads;
}
@@ -592,59 +605,59 @@ fat_read_super(struct super_block *sb, void *data, int silent,
if (i >= 0)
error = cvf_formats[i]->mount_cvf(sb,cvf_options);
else if (sb->s_blocksize == 512)
- MSDOS_SB(sb)->cvf_format = &default_cvf;
+ sbi->cvf_format = &default_cvf;
else
- MSDOS_SB(sb)->cvf_format = &bigblock_cvf;
+ sbi->cvf_format = &bigblock_cvf;
if (error || debug) {
/* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
"uid=%d,gid=%d,umask=%03o%s]\n",
- MSDOS_SB(sb)->fat_bits,opts.name_check,
+ sbi->fat_bits,opts.name_check,
opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
- MSDOS_CAN_BMAP(MSDOS_SB(sb)) ? ",bmap" : "");
+ MSDOS_CAN_BMAP(sbi) ? ",bmap" : "");
printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%ld,ds=%ld,de=%d,data=%ld,"
"se=%d,ts=%ld,ls=%d,rc=%ld,fc=%u]\n",
- b->media,MSDOS_SB(sb)->cluster_size,
- MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start,
- MSDOS_SB(sb)->fat_length,
- MSDOS_SB(sb)->dir_start,MSDOS_SB(sb)->dir_entries,
- MSDOS_SB(sb)->data_start,
+ b->media,sbi->cluster_size,
+ sbi->fats,sbi->fat_start,
+ sbi->fat_length,
+ sbi->dir_start,sbi->dir_entries,
+ sbi->data_start,
CF_LE_W(*(unsigned short *) &b->sectors),
(unsigned long)b->total_sect,logical_sector_size,
- MSDOS_SB(sb)->root_cluster,MSDOS_SB(sb)->free_clusters);
+ sbi->root_cluster,sbi->free_clusters);
printk ("Transaction block size = %d\n",blksize);
}
- if (i<0) if (MSDOS_SB(sb)->clusters+2 > fat_clusters)
- MSDOS_SB(sb)->clusters = fat_clusters-2;
+ if (i<0) if (sbi->clusters+2 > fat_clusters)
+ sbi->clusters = fat_clusters-2;
if (error)
goto out_invalid;
sb->s_magic = MSDOS_SUPER_MAGIC;
/* set up enough so that it can read an inode */
- init_waitqueue_head(&MSDOS_SB(sb)->fat_wait);
- init_MUTEX(&MSDOS_SB(sb)->fat_lock);
- MSDOS_SB(sb)->prev_free = 0;
+ init_waitqueue_head(&sbi->fat_wait);
+ init_MUTEX(&sbi->fat_lock);
+ sbi->prev_free = 0;
cp = opts.codepage ? opts.codepage : 437;
sprintf(buf, "cp%d", cp);
- MSDOS_SB(sb)->nls_disk = load_nls(buf);
- if (! MSDOS_SB(sb)->nls_disk) {
+ sbi->nls_disk = load_nls(buf);
+ if (! sbi->nls_disk) {
/* Fail only if explicit charset specified */
if (opts.codepage != 0)
goto out_fail;
- MSDOS_SB(sb)->options.codepage = 0; /* already 0?? */
- MSDOS_SB(sb)->nls_disk = load_nls_default();
+ sbi->options.codepage = 0; /* already 0?? */
+ sbi->nls_disk = load_nls_default();
}
- MSDOS_SB(sb)->nls_io = NULL;
- if (MSDOS_SB(sb)->options.isvfat && !opts.utf8) {
+ sbi->nls_io = NULL;
+ if (sbi->options.isvfat && !opts.utf8) {
p = opts.iocharset ? opts.iocharset : "iso8859-1";
- MSDOS_SB(sb)->nls_io = load_nls(p);
- if (! MSDOS_SB(sb)->nls_io) {
+ sbi->nls_io = load_nls(p);
+ if (! sbi->nls_io) {
/* Fail only if explicit charset specified */
if (opts.iocharset)
goto out_unload_nls;
- MSDOS_SB(sb)->nls_io = load_nls_default();
+ sbi->nls_io = load_nls_default();
}
}
@@ -660,7 +673,7 @@ fat_read_super(struct super_block *sb, void *data, int silent,
if (!sb->s_root)
goto out_no_root;
if(i>=0) {
- MSDOS_SB(sb)->cvf_format = cvf_formats[i];
+ sbi->cvf_format = cvf_formats[i];
++cvf_format_use_count[i];
}
return sb;
@@ -668,10 +681,10 @@ fat_read_super(struct super_block *sb, void *data, int silent,
out_no_root:
printk("get root inode failed\n");
iput(root_inode);
- if (MSDOS_SB(sb)->nls_io)
- unload_nls(MSDOS_SB(sb)->nls_io);
+ if (sbi->nls_io)
+ unload_nls(sbi->nls_io);
out_unload_nls:
- unload_nls(MSDOS_SB(sb)->nls_disk);
+ unload_nls(sbi->nls_disk);
goto out_fail;
out_invalid:
if (!silent)
@@ -686,8 +699,9 @@ out_fail:
kfree(opts.iocharset);
}
sb->s_dev = 0;
- if(MSDOS_SB(sb)->private_data)kfree(MSDOS_SB(sb)->private_data);
- MSDOS_SB(sb)->private_data=NULL;
+ if(sbi->private_data)
+ kfree(sbi->private_data);
+ sbi->private_data=NULL;
MOD_DEC_USE_COUNT;
return NULL;
@@ -737,21 +751,22 @@ static int is_exec(char *extension)
static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
{
struct super_block *sb = inode->i_sb;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
int nr;
INIT_LIST_HEAD(&MSDOS_I(inode)->i_fat_hash);
MSDOS_I(inode)->i_location = 0;
MSDOS_I(inode)->i_fat_inode = inode;
- inode->i_uid = MSDOS_SB(sb)->options.fs_uid;
- inode->i_gid = MSDOS_SB(sb)->options.fs_gid;
+ inode->i_uid = sbi->options.fs_uid;
+ inode->i_gid = sbi->options.fs_gid;
inode->i_version = ++event;
if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) {
inode->i_mode = MSDOS_MKMODE(de->attr,S_IRWXUGO &
- ~MSDOS_SB(sb)->options.fs_umask) | S_IFDIR;
- inode->i_op = MSDOS_SB(inode->i_sb)->dir_ops;
+ ~sbi->options.fs_umask) | S_IFDIR;
+ inode->i_op = sbi->dir_ops;
MSDOS_I(inode)->i_start = CF_LE_W(de->start);
- if (MSDOS_SB(sb)->fat_bits == 32) {
+ if (sbi->fat_bits == 32) {
MSDOS_I(inode)->i_start |=
(CF_LE_W(de->starthi) << 16);
}
@@ -767,8 +782,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
inode->i_size = 0;
if ((nr = MSDOS_I(inode)->i_start) != 0)
while (nr != -1) {
- inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->
- i_sb)->cluster_size;
+ inode->i_size += SECTOR_SIZE*sbi->cluster_size;
if (!(nr = fat_access(sb,nr,-1))) {
printk("Directory %ld: bad FAT\n",
inode->i_ino);
@@ -779,13 +793,13 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
} else { /* not a directory */
inode->i_mode = MSDOS_MKMODE(de->attr,
((IS_NOEXEC(inode) ||
- (MSDOS_SB(sb)->options.showexec &&
+ (sbi->options.showexec &&
!is_exec(de->ext)))
? S_IRUGO|S_IWUGO : S_IRWXUGO)
- & ~MSDOS_SB(sb)->options.fs_umask) | S_IFREG;
+ & ~sbi->options.fs_umask) | S_IFREG;
inode->i_op = &fat_file_inode_operations;
MSDOS_I(inode)->i_start = CF_LE_W(de->start);
- if (MSDOS_SB(sb)->fat_bits == 32) {
+ if (sbi->fat_bits == 32) {
MSDOS_I(inode)->i_start |=
(CF_LE_W(de->starthi) << 16);
}
@@ -795,13 +809,14 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
MSDOS_I(inode)->i_realsize = ((inode->i_size-1)|(SECTOR_SIZE-1))+1;
}
if(de->attr & ATTR_SYS)
- if (MSDOS_SB(sb)->options.sys_immutable)
+ if (sbi->options.sys_immutable)
inode->i_flags |= S_IMMUTABLE;
MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
/* this is as close to the truth as we can get ... */
- inode->i_blksize = MSDOS_SB(sb)->cluster_size*SECTOR_SIZE;
- inode->i_blocks = (inode->i_size+inode->i_blksize-1)/
- inode->i_blksize*MSDOS_SB(sb)->cluster_size;
+ inode->i_blksize = sbi->cluster_size*SECTOR_SIZE;
+ inode->i_blocks =
+ ((inode->i_size+inode->i_blksize-1)>>sbi->cluster_bits) *
+ sbi->cluster_size;
inode->i_mtime = inode->i_atime =
date_dos2unix(CF_LE_W(de->time),CF_LE_W(de->date));
inode->i_ctime =
diff --git a/fs/file.c b/fs/file.c
index d62fb3ef3..7bdf29179 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -64,7 +64,7 @@ int expand_fd_array(struct files_struct *files, int nr)
error = -EMFILE;
- if (files->max_fds >= NR_OPEN || nr > NR_OPEN)
+ if (files->max_fds >= NR_OPEN || nr >= NR_OPEN)
goto out;
nfds = files->max_fds;
@@ -88,7 +88,7 @@ int expand_fd_array(struct files_struct *files, int nr)
if (nfds > NR_OPEN)
nfds = NR_OPEN;
}
- } while (nfds < nr);
+ } while (nfds <= nr);
error = -ENOMEM;
new_fds = alloc_fd_array(nfds);
@@ -175,7 +175,7 @@ int expand_fdset(struct files_struct *files, int nr)
int error, nfds = 0;
error = -EMFILE;
- if (files->max_fdset >= NR_OPEN || nr > NR_OPEN)
+ if (files->max_fdset >= NR_OPEN || nr >= NR_OPEN)
goto out;
nfds = files->max_fdset;
@@ -190,7 +190,7 @@ int expand_fdset(struct files_struct *files, int nr)
if (nfds > NR_OPEN)
nfds = NR_OPEN;
}
- } while (nfds < nr);
+ } while (nfds <= nr);
error = -ENOMEM;
new_openset = alloc_fdset(nfds);
diff --git a/fs/filesystems.c b/fs/filesystems.c
index b05b3b657..da67d4d52 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -30,6 +30,7 @@
#include <linux/ntfs_fs.h>
#include <linux/hfs_fs.h>
#include <linux/devpts_fs.h>
+#include <linux/bfs_fs.h>
#include <linux/major.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -154,6 +155,10 @@ void __init filesystem_setup(void)
#ifdef CONFIG_UDF_FS
init_udf_fs();
#endif
+
+#ifdef CONFIG_BFS_FS
+ init_bfs_fs();
+#endif
#ifdef CONFIG_NLS
init_nls();
diff --git a/fs/hfs/file.c b/fs/hfs/file.c
index 6b01cd9e0..594d65271 100644
--- a/fs/hfs/file.c
+++ b/fs/hfs/file.c
@@ -498,7 +498,6 @@ hfs_s32 hfs_do_write(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos,
written = -EFAULT;
break;
}
- update_vm_cache(inode,pos,p,c);
pos += c;
written += c;
buf += c;
diff --git a/fs/inode.c b/fs/inode.c
index bb4e0031f..811bf575d 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -518,8 +518,7 @@ static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, s
spin_lock(&inode_lock);
/* We released the lock, so.. */
old = find_inode(sb, ino, head, find_actor, opaque);
- if (!old)
- {
+ if (!old) {
list_add(&inode->i_list, &inode_in_use);
list_add(&inode->i_hash, head);
inode->i_sb = sb;
@@ -546,7 +545,13 @@ static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, s
return inode;
}
- __iget(inode);
+
+ /*
+ * Uhhuh, somebody else created the same inode under
+ * us. Use the old inode instead of the one we just
+ * allocated.
+ */
+ __iget(old);
spin_unlock(&inode_lock);
destroy_inode(inode);
inode = old;
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 8001c5186..8da9396cc 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -1009,7 +1009,7 @@ abort_negative:
abort_beyond_end:
printk("_isofs_bmap: block >= EOF (%ld, %ld)\n",
- iblock, inode->i_size);
+ iblock, (unsigned long) inode->i_size);
goto abort;
abort_too_many_sections:
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 795425201..dee4f28e7 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -195,6 +195,12 @@ xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
#define SM_my_id_sz (3+1+SM_my_name_sz)
#define SM_mon_id_sz (1+XDR_QUADLEN(20)+SM_my_id_sz)
#define SM_mon_sz (SM_mon_id_sz+4)
+#define SM_monres_sz 2
+#define SM_unmonres_sz 1
+
+#ifndef MAX
+# define MAX(a, b) (((a) > (b))? (a) : (b))
+#endif
static struct rpc_procinfo nsm_procedures[] = {
{ "sm_null",
@@ -205,10 +211,10 @@ static struct rpc_procinfo nsm_procedures[] = {
(kxdrproc_t) xdr_error, 0, 0 },
{ "sm_mon",
(kxdrproc_t) xdr_encode_mon,
- (kxdrproc_t) xdr_decode_stat_res, SM_mon_sz, 2 },
+ (kxdrproc_t) xdr_decode_stat_res, MAX(SM_mon_sz, SM_monres_sz) << 2, 0 },
{ "sm_unmon",
(kxdrproc_t) xdr_encode_mon,
- (kxdrproc_t) xdr_decode_stat, SM_mon_id_sz, 1 },
+ (kxdrproc_t) xdr_decode_stat, MAX(SM_mon_id_sz, SM_unmonres_sz) << 2, 0 },
{ "sm_unmon_all",
(kxdrproc_t) xdr_error,
(kxdrproc_t) xdr_error, 0, 0 },
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 060d5b26c..21057e7dc 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -251,13 +251,15 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
struct buffer_head * bh;
int i,j;
- if (!dir || !(inode = get_empty_inode()))
+ inode = get_empty_inode();
+ if (!inode)
return NULL;
sb = dir->i_sb;
inode->i_sb = sb;
inode->i_flags = 0;
j = 8192;
bh = NULL;
+ lock_super(sb);
for (i = 0; i < sb->u.minix_sb.s_imap_blocks; i++) {
bh = inode->i_sb->u.minix_sb.s_imap[i];
if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
@@ -265,17 +267,20 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
}
if (!bh || j >= 8192) {
iput(inode);
+ unlock_super(sb);
return NULL;
}
if (minix_set_bit(j,bh->b_data)) { /* shouldn't happen */
printk("new_inode: bit already set");
iput(inode);
+ unlock_super(sb);
return NULL;
}
mark_buffer_dirty(bh, 1);
j += i*8192;
if (!j || j > inode->i_sb->u.minix_sb.s_ninodes) {
iput(inode);
+ unlock_super(sb);
return NULL;
}
inode->i_nlink = 1;
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index d3af541dd..4ed7a9abe 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -26,8 +26,10 @@
#include "ncplib_kernel.h"
-static int ncp_read_volume_list(struct file *, void *, filldir_t);
-static int ncp_do_readdir(struct file *, void *, filldir_t);
+static void ncp_read_volume_list(struct file *, void *, filldir_t,
+ struct ncp_cache_control *);
+static void ncp_do_readdir(struct file *, void *, filldir_t,
+ struct ncp_cache_control *);
static ssize_t ncp_dir_read(struct file *, char *, size_t, loff_t *);
static int ncp_readdir(struct file *, void *, filldir_t);
@@ -171,10 +173,8 @@ ncp_delete_dentry(struct dentry * dentry)
* (Somebody might have used it again ...)
*/
if (dentry->d_count == 1 && NCP_FINFO(inode)->opened) {
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_delete_dentry: closing file %s/%s\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
+ PPRINTK("ncp_delete_dentry: closing file %s/%s\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
ncp_make_closed(inode);
}
} else
@@ -310,7 +310,7 @@ ncp_lookup_validate(struct dentry * dentry, int flags)
if (!dentry->d_inode || !dir)
goto finished;
-
+
server = NCP_SERVER(dir);
if (!ncp_conn_valid(server))
@@ -325,19 +325,18 @@ ncp_lookup_validate(struct dentry * dentry, int flags)
val = NCP_TEST_AGE(server, dentry);
if (val)
goto finished;
-#ifdef NCPFS_PARANOIA
- printk(KERN_DEBUG "ncp_lookup_validate: %s/%s not valid, age=%ld\n",
+
+ PPRINTK("ncp_lookup_validate: %s/%s not valid, age=%ld\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
NCP_GET_AGE(dentry));
-#endif
memcpy(__name, dentry->d_name.name, len);
__name[len] = '\0';
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_lookup_validate: %s, len %d\n", __name, len);
-printk(KERN_DEBUG "ncp_lookup_validate: server lookup for %s/%s\n",
-dentry->d_parent->d_name.name, __name);
-#endif
+
+ PPRINTK("ncp_lookup_validate: %s, len %d\n", __name, len);
+ PPRINTK("ncp_lookup_validate: server lookup for %s/%s\n",
+ dentry->d_parent->d_name.name, __name);
+
if (ncp_is_server_root(dir)) {
io2vol(server, __name, 1);
res = ncp_lookup_volume(server, __name, &(finfo.i));
@@ -345,10 +344,8 @@ dentry->d_parent->d_name.name, __name);
io2vol(server, __name, !ncp_preserve_case(dir));
res = ncp_obtain_info(server, dir, __name, &(finfo.i));
}
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_lookup_validate: looked for %s/%s, res=%d\n",
-dentry->d_parent->d_name.name, __name, res);
-#endif
+ PPRINTK("ncp_lookup_validate: looked for %s/%s, res=%d\n",
+ dentry->d_parent->d_name.name, __name, res);
/*
* If we didn't find it, or if it has a different dirEntNum to
* what we remember, it's not valid any more.
@@ -356,359 +353,435 @@ dentry->d_parent->d_name.name, __name, res);
if (!res) {
if (finfo.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum)
val=1;
-#ifdef NCPFS_PARANOIA
else
- printk(KERN_DEBUG "ncp_lookup_validate: found, but dirEntNum changed\n");
-#endif
+ PPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n");
+
vol2io(server, finfo.i.entryName,
!ncp_preserve_entry_case(dir, finfo.i.NSCreator));
ncp_update_inode2(dentry->d_inode, &finfo);
- ncp_new_dentry(dentry);
+ if (val)
+ ncp_new_dentry(dentry);
}
finished:
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_lookup_validate: result=%d\n", val);
-#endif
-
+ PPRINTK("ncp_lookup_validate: result=%d\n", val);
return val;
}
+static struct page *
+ncp_get_cache_page(struct inode *inode, unsigned long offset, int used)
+{
+ struct address_space *i_data = &inode->i_data;
+ struct page *new_page, *page, **hash;
+
+ hash = page_hash(i_data, offset);
+
+ page = __find_lock_page(i_data, offset, hash);
+ if (used || page)
+ return page;
+
+ new_page = page_cache_alloc();
+ if (!new_page)
+ return NULL;
+
+ for (;;) {
+ page = new_page;
+ if (!add_to_page_cache_unique(page, i_data, offset, hash))
+ break;
+ page_cache_release(page);
+ page = __find_lock_page(i_data, offset, hash);
+ if (page) {
+ page_cache_free(new_page);
+ break;
+ }
+ }
+
+ return page;
+}
+
+/* most parts from nfsd_d_validate() */
+static int
+ncp_d_validate(struct dentry *dentry)
+{
+ unsigned long dent_addr = (unsigned long) dentry;
+ unsigned long min_addr = PAGE_OFFSET;
+ unsigned long align_mask = 0x0F;
+ unsigned int len;
+ int valid = 0;
+
+ if (dent_addr < min_addr)
+ goto bad_addr;
+ if (dent_addr > (unsigned long)high_memory - sizeof(struct dentry))
+ goto bad_addr;
+ if ((dent_addr & ~align_mask) != dent_addr)
+ goto bad_align;
+ if (!kern_addr_valid(dent_addr))
+ goto bad_addr;
+ /*
+ * Looks safe enough to dereference ...
+ */
+ len = dentry->d_name.len;
+ if (len > NCP_MAXPATHLEN)
+ goto out;
+ /*
+ * Note: d_validate doesn't dereference the parent pointer ...
+ * just combines it with the name hash to find the hash chain.
+ */
+ valid = d_validate(dentry, dentry->d_parent, dentry->d_name.hash, len);
+out:
+ return valid;
+
+bad_addr:
+ PRINTK("ncp_d_validate: invalid address %lx\n", dent_addr);
+ goto out;
+bad_align:
+ PRINTK("ncp_d_validate: unaligned address %lx\n", dent_addr);
+ goto out;
+}
+
+static struct dentry *
+ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
+{
+ struct dentry *dent = dentry;
+ struct list_head *next;
+
+ if (ncp_d_validate(dent))
+ if ((dent->d_parent == parent) &&
+ ((unsigned long)dent->d_fsdata == fpos))
+ goto out;
+
+ /* If a pointer is invalid, we search the dentry. */
+ next = parent->d_subdirs.next;
+ while (next != &parent->d_subdirs) {
+ dent = list_entry(next, struct dentry, d_child);
+ if ((unsigned long)dent->d_fsdata == fpos)
+ goto out;
+ next = next->next;
+ }
+ dent = NULL;
+out:
+ if (dent)
+ if (dent->d_inode)
+ return dget(dent);
+ return NULL;
+}
+
+static time_t ncp_obtain_mtime(struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ struct ncp_server *server = NCP_SERVER(inode);
+ struct nw_info_struct i;
+
+ if (!ncp_conn_valid(server) ||
+ ncp_is_server_root(inode))
+ return 0;
+
+ if (ncp_obtain_info(server, inode, NULL, &i))
+ return 0;
+
+ return ncp_date_dos2unix(le16_to_cpu(i.modifyTime),
+ le16_to_cpu(i.modifyDate));
+}
static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct dentry *dentry = filp->f_dentry;
struct inode *inode = dentry->d_inode;
+ struct page *page = NULL;
struct ncp_server *server = NCP_SERVER(inode);
- int entries, result;
+ union ncp_dir_cache *cache = NULL;
+ struct ncp_cache_control ctl;
+ int result, mtime_valid = 0;
+ time_t mtime = 0;
- DDPRINTK(KERN_DEBUG "ncp_readdir: reading %s/%s, pos=%d\n",
+ ctl.page = NULL;
+ ctl.cache = NULL;
+
+ DDPRINTK("ncp_readdir: reading %s/%s, pos=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
(int) filp->f_pos);
result = -EIO;
if (!ncp_conn_valid(server))
- goto finished;
+ goto out;
result = 0;
if (filp->f_pos == 0) {
if (filldir(dirent, ".", 1, 0, inode->i_ino))
- goto finished;
+ goto out;
filp->f_pos = 1;
}
if (filp->f_pos == 1) {
if (filldir(dirent, "..", 2, 1,
dentry->d_parent->d_inode->i_ino))
- goto finished;
+ goto out;
filp->f_pos = 2;
}
- if (ncp_is_server_root(inode)) {
- entries = ncp_read_volume_list(filp, dirent, filldir);
- DPRINTK(KERN_DEBUG "ncp_read_volume_list returned %d\n", entries);
- } else {
- entries = ncp_do_readdir(filp, dirent, filldir);
- DPRINTK(KERN_DEBUG "ncp_readdir: returned %d\n", entries);
+ page = ncp_get_cache_page(inode, 0, 0);
+ if (!page)
+ goto read_really;
+
+ ctl.cache = cache = (union ncp_dir_cache *) page_address(page);
+ ctl.head = cache->head;
+
+ if (!Page_Uptodate(page) || !ctl.head.eof)
+ goto init_cache;
+
+ if (filp->f_pos == 2) {
+ if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
+ goto init_cache;
+
+ mtime = ncp_obtain_mtime(dentry);
+ mtime_valid = 1;
+ if ((!mtime) || (mtime != ctl.head.mtime))
+ goto init_cache;
}
- if (entries < 0)
- result = entries;
+ if (filp->f_pos > ctl.head.end)
+ goto finished;
+
+ ctl.fpos = filp->f_pos + (NCP_DIRCACHE_START - 2);
+ ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE;
+ ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE;
+ for (;;) {
+ if (ctl.ofs != 0) {
+ ctl.page = ncp_get_cache_page(inode, ctl.ofs, 1);
+ if (!ctl.page)
+ goto invalid_cache;
+ if (!Page_Uptodate(ctl.page))
+ goto invalid_cache;
+ ctl.cache = (union ncp_dir_cache *)
+ page_address(ctl.page);
+ }
+ while (ctl.idx < NCP_DIRCACHE_SIZE) {
+ struct dentry *dent;
+ int res;
+
+ dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx],
+ dentry, filp->f_pos);
+ if (!dent)
+ goto invalid_cache;
+ res = filldir(dirent, dent->d_name.name,
+ dent->d_name.len, filp->f_pos,
+ dent->d_inode->i_ino);
+ dput(dent);
+ if (res)
+ goto finished;
+ filp->f_pos += 1;
+ ctl.idx += 1;
+ if (filp->f_pos > ctl.head.end)
+ goto finished;
+ }
+ if (ctl.page) {
+ SetPageUptodate(ctl.page);
+ UnlockPage(ctl.page);
+ page_cache_release(ctl.page);
+ ctl.page = NULL;
+ }
+ ctl.idx = 0;
+ ctl.ofs += 1;
+ }
+invalid_cache:
+ if (ctl.page) {
+ UnlockPage(ctl.page);
+ page_cache_release(ctl.page);
+ ctl.page = NULL;
+ }
+ ctl.cache = cache;
+init_cache:
+ ncp_invalidate_dircache_entries(dentry);
+ if (!mtime_valid) {
+ mtime = ncp_obtain_mtime(dentry);
+ mtime_valid = 1;
+ }
+ ctl.head.mtime = mtime;
+ ctl.head.time = jiffies;
+ ctl.head.eof = 0;
+ ctl.fpos = 2;
+ ctl.ofs = 0;
+ ctl.idx = NCP_DIRCACHE_START;
+ ctl.filled = 0;
+ ctl.valid = 1;
+read_really:
+ if (ncp_is_server_root(inode)) {
+ ncp_read_volume_list(filp, dirent, filldir, &ctl);
+ } else {
+ ncp_do_readdir(filp, dirent, filldir, &ctl);
+ }
+ ctl.head.end = ctl.fpos - 1;
+ ctl.head.eof = ctl.valid;
finished:
+ if (page) {
+ cache->head = ctl.head;
+ SetPageUptodate(page);
+ UnlockPage(page);
+ page_cache_release(page);
+ }
+ if (ctl.page) {
+ SetPageUptodate(ctl.page);
+ UnlockPage(ctl.page);
+ page_cache_release(ctl.page);
+ }
+out:
return result;
}
static int
-ncp_do_simple_filldir(struct file *filp, char* name, int len,
- void* dirent, filldir_t filldir)
+ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+ struct ncp_cache_control *ctrl, struct ncp_entry_info *entry)
{
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *newdent, *dentry = filp->f_dentry;
+ struct inode *newino, *inode = dentry->d_inode;
+ struct ncp_server *server = NCP_SERVER(inode);
+ struct ncp_cache_control ctl = *ctrl;
struct qstr qname;
ino_t ino = 0;
- int result;
-
- qname.name = name;
- qname.len = len;
-
- ino = find_inode_number(dentry, &qname);
+ int valid = 0;
- if (!ino)
- ino = iunique(dentry->d_inode->i_sb, 2);
+ vol2io(server, entry->i.entryName,
+ !ncp_preserve_entry_case(inode, entry->i.NSCreator));
- result = filldir(dirent, name, len, filp->f_pos, ino);
- if (!result)
- filp->f_pos += 1;
-
- return result;
-}
-
-static int
-ncp_do_filldir(struct file *filp, struct ncp_entry_info *entry, void *dirent,
- filldir_t filldir)
-{
- struct dentry *dentry = filp->f_dentry;
- struct inode *inode = dentry->d_inode;
- struct qstr qname;
- ino_t ino = 0;
- int result;
-
- /* For getwd() we have to return the correct inode in d_ino if the
- * inode is currently in use. Otherwise the inode number does not
- * matter. (You can argue a lot about this..)
- */
qname.name = entry->i.entryName;
qname.len = entry->i.nameLen;
+ qname.hash = full_name_hash(qname.name, qname.len);
- {
- struct dentry *newdent;
- struct inode *newino;
-
- qname.hash = full_name_hash(qname.name, qname.len);
- if (dentry->d_op && dentry->d_op->d_hash)
- if (dentry->d_op->d_hash(dentry, &qname) != 0)
- goto end_advance;
-
- newdent = d_lookup(dentry, &qname);
+ if (dentry->d_op && dentry->d_op->d_hash)
+ if (dentry->d_op->d_hash(dentry, &qname) != 0)
+ goto end_advance;
- if (!newdent) {
- newdent = d_alloc(dentry, &qname);
- if (!newdent)
- goto end_advance;
- }
+ newdent = d_lookup(dentry, &qname);
- if (!newdent->d_inode) {
- entry->opened = 0;
- entry->ino = iunique(inode->i_sb, 2);
- newino = ncp_iget(inode->i_sb, entry);
- if (newino) {
- newdent->d_op = &ncp_dentry_operations;
- d_add(newdent, newino);
- ncp_new_dentry(newdent);
- }
- } else {
- ncp_update_inode2(newdent->d_inode, entry);
- ncp_new_dentry(newdent);
+ if (!newdent) {
+ newdent = d_alloc(dentry, &qname);
+ if (!newdent)
+ goto end_advance;
+ } else
+ memcpy((char *) newdent->d_name.name, qname.name,
+ newdent->d_name.len);
+
+ if (!newdent->d_inode) {
+ entry->opened = 0;
+ entry->ino = iunique(inode->i_sb, 2);
+ newino = ncp_iget(inode->i_sb, entry);
+ if (newino) {
+ newdent->d_op = &ncp_dentry_operations;
+ d_add(newdent, newino);
}
+ } else
+ ncp_update_inode2(newdent->d_inode, entry);
- if (newdent->d_inode)
- ino = newdent->d_inode->i_ino;
-
- dput(newdent);
+ if (newdent->d_inode) {
+ ino = newdent->d_inode->i_ino;
+ newdent->d_fsdata = (void *) ctl.fpos;
+ ncp_new_dentry(newdent);
+ }
+ if (ctl.idx >= NCP_DIRCACHE_SIZE) {
+ if (ctl.page) {
+ SetPageUptodate(ctl.page);
+ UnlockPage(ctl.page);
+ page_cache_release(ctl.page);
+ }
+ ctl.cache = NULL;
+ ctl.idx -= NCP_DIRCACHE_SIZE;
+ ctl.ofs += 1;
+ ctl.page = ncp_get_cache_page(inode, ctl.ofs, 0);
+ if (ctl.page)
+ ctl.cache = (union ncp_dir_cache *)
+ page_address(ctl.page);
+ }
+ if (ctl.cache) {
+ ctl.cache->dentry[ctl.idx] = newdent;
+ valid = 1;
+ }
+ dput(newdent);
end_advance:
+ if (!valid)
+ ctl.valid = 0;
+ if (!ctl.filled && (ctl.fpos == filp->f_pos)) {
+ if (!ino)
+ ino = find_inode_number(dentry, &qname);
+ if (!ino)
+ ino = iunique(inode->i_sb, 2);
+ ctl.filled = filldir(dirent, entry->i.entryName,
+ entry->i.nameLen, filp->f_pos, ino);
+ if (!ctl.filled)
+ filp->f_pos += 1;
}
- if (!ino)
- ino = find_inode_number(dentry, &qname);
-
- if (!ino)
- ino = iunique(inode->i_sb, 2);
-
- result = filldir(dirent, entry->i.entryName, entry->i.nameLen,
- filp->f_pos, ino);
- if (!result)
- filp->f_pos += 1;
-
- return result;
+ ctl.fpos += 1;
+ ctl.idx += 1;
+ *ctrl = ctl;
+ return (ctl.valid || !ctl.filled);
}
-static int
-ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir)
+static void
+ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir,
+ struct ncp_cache_control *ctl)
{
struct dentry *dentry = filp->f_dentry;
struct inode *inode = dentry->d_inode;
struct ncp_server *server = NCP_SERVER(inode);
struct ncp_volume_info info;
struct ncp_entry_info entry;
- unsigned long total_count = 2, fpos = filp->f_pos;
int i;
- DPRINTK(KERN_DEBUG "ncp_read_volume_list: pos=%ld\n", fpos);
+ DPRINTK("ncp_read_volume_list: pos=%ld\n",
+ (unsigned long) filp->f_pos);
for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
if (ncp_get_volume_info_with_number(server, i, &info) != 0)
- break;
+ return;
if (!strlen(info.volume_name))
continue;
- if (total_count < fpos) {
- DPRINTK(KERN_DEBUG "ncp_read_volume_list: skipped vol: %s\n",
- info.volume_name);
- } else {
- DPRINTK(KERN_DEBUG "ncp_read_volume_list: found vol: %s\n",
- info.volume_name);
+ DPRINTK("ncp_read_volume_list: found vol: %s\n",
+ info.volume_name);
- if (ncp_lookup_volume(server, info.volume_name,
- &entry.i)) {
- DPRINTK(KERN_DEBUG "ncpfs: could not lookup vol %s\n",
- info.volume_name);
- continue;
- }
- vol2io(server, entry.i.entryName,
- !ncp_preserve_entry_case(inode, entry.i.NSCreator));
- if (ncp_do_filldir(filp, &entry, dirent, filldir))
- break;
+ if (ncp_lookup_volume(server, info.volume_name,
+ &entry.i)) {
+ DPRINTK("ncpfs: could not lookup vol %s\n",
+ info.volume_name);
+ continue;
}
- total_count += 1;
+ if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry))
+ return;
}
-
- return (total_count - fpos);
}
-static int ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static void ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
+ struct ncp_cache_control *ctl)
{
struct dentry *dentry = filp->f_dentry;
struct inode *dir = dentry->d_inode;
struct ncp_server *server = NCP_SERVER(dir);
- struct ncp_seq_cache *cache = NULL;
- struct ncp_cache_control ctl;
+ struct nw_search_sequence seq;
struct ncp_entry_info entry;
- struct page *page, **hash;
- unsigned long total_count = 0, fpos = filp->f_pos;
int err;
- DPRINTK(KERN_DEBUG "ncp_do_readdir: %s/%s, fpos=%ld\n",
- dentry->d_parent->d_name.name, dentry->d_name.name, fpos);
-
-#ifdef NCPFS_DEBUG_VERBOSE
-printk("ncp_do_readdir: finding cache for %s/%s\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
-
- /* cache using inspired by smbfs and nfs */
- hash = page_hash(&dir->i_data, 0);
-
- page = __find_lock_page(&dir->i_data, 0, hash);
-
- if (!page) {
- unsigned long page_cache;
-
- page_cache = page_cache_alloc();
- if (page_cache) {
- page = page_cache_entry(page_cache);
- if (add_to_page_cache_unique(page, &dir->i_data, 0, hash)) {
- page_cache_release(page);
- page = NULL;
- page_cache_free(page_cache);
- }
- }
- }
-
- if (!page)
- goto start_search;
-
- cache = (struct ncp_seq_cache *) page_address(page);
- ctl = cache->ctl;
-
- if (!Page_Uptodate(page))
- ctl.currentpos = NCP_FPOS_EMPTY;
-
- if ((fpos == 2) || (fpos < ctl.firstcache))
- ctl.currentpos = NCP_FPOS_EMPTY;
-
- if (ctl.currentpos == NCP_FPOS_EMPTY)
- goto start_search;
-
- {
- int fetchpos = ctl.cachehead;
- int readpos = ctl.firstcache;
-
- while (readpos < fpos) {
- fetchpos += cache->cache[fetchpos] + 1;
- readpos++;
- }
- while (fpos < ctl.currentpos) {
- err = ncp_do_simple_filldir(filp,
- (char*)(cache->cache+fetchpos+1),
- cache->cache[fetchpos],
- dirent, filldir);
- if (err)
- goto out;
- fetchpos += cache->cache[fetchpos] + 1;
- fpos++;
- total_count++;
- }
+ DPRINTK("ncp_do_readdir: %s/%s, fpos=%ld\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ (unsigned long) filp->f_pos);
+ PPRINTK("ncp_do_readdir: init %s, volnum=%d, dirent=%u\n",
+ dentry->d_name.name, NCP_FINFO(dir)->volNumber,
+ NCP_FINFO(dir)->dirEntNum);
+
+ err = ncp_initialize_search(server, dir, &seq);
+ if (err) {
+ DPRINTK("ncp_do_readdir: init failed, err=%d\n", err);
+ return;
}
-
-start_search:
-
- DDPRINTK(KERN_DEBUG "ncp_do_readdir: %s: f_pos=%ld,total_count=%ld\n",
- dentry->d_name.name, fpos, total_count);
-
- if (ctl.currentpos == NCP_FPOS_EMPTY) {
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_do_readdir: init %s, volnum=%d, dirent=%u\n",
-dentry->d_name.name, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
-#endif
- err = ncp_initialize_search(server, dir, &ctl.seq);
- if (err) {
- DPRINTK(KERN_DEBUG "ncp_do_readdir: init failed, err=%d\n", err);
- goto out;
- }
- ctl.eof = 0;
- ctl.cachehead = ctl.cachetail = 0;
- ctl.firstcache = ctl.currentpos = 2;
- } else
- DDPRINTK(KERN_DEBUG "ncp_do_readdir: reused seq for %s, fpos=%li\n",
- dentry->d_name.name, total_count);
-
for (;;) {
- err = ncp_search_for_file_or_subdir(server, &ctl.seq,
- &entry.i);
+ err = ncp_search_for_file_or_subdir(server, &seq, &entry.i);
if (err) {
- DPRINTK(KERN_DEBUG "ncp_do_readdir: search failed, err=%d\n", err);
- ctl.eof = 1;
- break;
+ DPRINTK("ncp_do_readdir: search failed, err=%d\n", err);
+ return;
}
-
- ctl.currentpos++;
-
- vol2io(server, entry.i.entryName,
- !ncp_preserve_entry_case(dir, entry.i.NSCreator));
-
- if (page) {
- int tlen = ctl.cachetail + entry.i.nameLen + 1;
-
- if (tlen > NCP_DIRCACHE_SIZE) {
- int ofs = ctl.cachehead;
-
- while (tlen - ofs > NCP_DIRCACHE_SIZE) {
- ofs += cache->cache[ofs] + 1;
- ctl.firstcache++;
- }
- ctl.cachetail -= ofs;
- memmove(cache->cache+0,
- cache->cache+ofs,
- ctl.cachetail);
- }
- cache->cache[ctl.cachetail++] = entry.i.nameLen;
- memcpy(cache->cache+ctl.cachetail,
- entry.i.entryName, entry.i.nameLen);
- ctl.cachetail += entry.i.nameLen;
- }
- if (ctl.currentpos < fpos) {
- DPRINTK(KERN_DEBUG "ncp_do_readdir: skipped file: %s/%s\n",
- dentry->d_name.name, entry.i.entryName);
- } else {
- DDPRINTK(KERN_DEBUG "ncp_do_r: file: %s, f_pos=%ld,total_count=%ld",
- entry.i.entryName, fpos, total_count);
- if (ncp_do_filldir(filp, &entry, dirent, filldir))
- break;
- }
- total_count++;
- fpos++;
+ if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry))
+ return;
}
-out:
- if (page) {
- cache->ctl = ctl;
- SetPageUptodate(page);
- UnlockPage(page);
- page_cache_release(page);
- }
-
- DDPRINTK(KERN_DEBUG "ncp_do_readdir: %s: return=%ld\n",
- dentry->d_name.name, total_count);
- return total_count;
}
int ncp_conn_logged_in(struct super_block *sb)
@@ -723,9 +796,8 @@ int ncp_conn_logged_in(struct super_block *sb)
result = -ENOENT;
io2vol(server, server->m.mounted_vol, 1);
if (ncp_lookup_volume(server, server->m.mounted_vol, &i)) {
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_conn_logged_in: %s not found\n", server->m.mounted_vol);
-#endif
+ PPRINTK("ncp_conn_logged_in: %s not found\n",
+ server->m.mounted_vol);
goto out;
}
vol2io(server, i.entryName, 1);
@@ -737,10 +809,10 @@ printk(KERN_DEBUG "ncp_conn_logged_in: %s not found\n", server->m.mounted_vol);
NCP_FINFO(ino)->dirEntNum = i.dirEntNum;
NCP_FINFO(ino)->DosDirNum = i.DosDirNum;
} else {
- DPRINTK(KERN_DEBUG "ncpfs: sb->s_root->d_inode == NULL!\n");
+ DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n");
}
} else {
- DPRINTK(KERN_DEBUG "ncpfs: sb->s_root == NULL!\n");
+ DPRINTK("ncpfs: sb->s_root == NULL!\n");
}
}
result = 0;
@@ -765,11 +837,9 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry)
memcpy(__name, dentry->d_name.name, len);
__name[len] = '\0';
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_lookup: %s, len %d\n", __name, len);
-printk(KERN_DEBUG "ncp_lookup: server lookup for %s/%s\n",
-dentry->d_parent->d_name.name, __name);
-#endif
+ PPRINTK("ncp_lookup: %s, len %d\n", __name, len);
+ PPRINTK("ncp_lookup: server lookup for %s/%s\n",
+ dentry->d_parent->d_name.name, __name);
if (ncp_is_server_root(dir)) {
io2vol(server, __name, 1);
res = ncp_lookup_volume(server, __name, &(finfo.i));
@@ -777,10 +847,8 @@ dentry->d_parent->d_name.name, __name);
io2vol(server, __name, !ncp_preserve_case(dir));
res = ncp_obtain_info(server, dir, __name, &(finfo.i));
}
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_lookup: looked for %s/%s, res=%d\n",
-dentry->d_parent->d_name.name, __name, res);
-#endif
+ PPRINTK("ncp_lookup: looked for %s/%s, res=%d\n",
+ dentry->d_parent->d_name.name, __name, res);
/*
* If we didn't find an entry, make a negative dentry.
*/
@@ -807,9 +875,7 @@ add_entry:
}
finished:
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_lookup: result=%d\n", error);
-#endif
+ PPRINTK("ncp_lookup: result=%d\n", error);
return ERR_PTR(error);
}
@@ -832,10 +898,8 @@ out:
return error;
out_close:
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_instantiate: %s/%s failed, closing file\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
+ PPRINTK("ncp_instantiate: %s/%s failed, closing file\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
goto out;
}
@@ -848,10 +912,8 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
struct ncp_server *server = NCP_SERVER(dir);
__u8 _name[dentry->d_name.len + 1];
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_create_new: creating %s/%s, mode=%x\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, mode);
-#endif
+ PPRINTK("ncp_create_new: creating %s/%s, mode=%x\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name, mode);
error = -EIO;
if (!ncp_conn_valid(server))
goto out;
@@ -872,7 +934,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, mode);
error = ncp_instantiate(dir, dentry, &finfo);
} else {
if (result == 0x87) error = -ENAMETOOLONG;
- DPRINTK(KERN_DEBUG "ncp_create: %s/%s failed\n",
+ DPRINTK("ncp_create: %s/%s failed\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
}
@@ -892,7 +954,7 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
struct ncp_server *server = NCP_SERVER(dir);
__u8 _name[dentry->d_name.len + 1];
- DPRINTK(KERN_DEBUG "ncp_mkdir: making %s/%s\n",
+ DPRINTK("ncp_mkdir: making %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
error = -EIO;
if (!ncp_conn_valid(server))
@@ -921,7 +983,7 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
struct ncp_server *server = NCP_SERVER(dir);
__u8 _name[dentry->d_name.len + 1];
- DPRINTK(KERN_DEBUG "ncp_rmdir: removing %s/%s\n",
+ DPRINTK("ncp_rmdir: removing %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
error = -EIO;
@@ -972,7 +1034,7 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry)
struct ncp_server *server = NCP_SERVER(dir);
int error;
- DPRINTK(KERN_DEBUG "ncp_unlink: unlinking %s/%s\n",
+ DPRINTK("ncp_unlink: unlinking %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
error = -EIO;
@@ -983,9 +1045,7 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry)
* Check whether to close the file ...
*/
if (inode && NCP_FINFO(inode)->opened) {
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_unlink: closing file\n");
-#endif
+ PPRINTK("ncp_unlink: closing file\n");
ncp_make_closed(inode);
}
@@ -999,7 +1059,7 @@ printk(KERN_DEBUG "ncp_unlink: closing file\n");
#endif
switch (error) {
case 0x00:
- DPRINTK(KERN_DEBUG "ncp: removed %s/%s\n",
+ DPRINTK("ncp: removed %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
d_delete(dentry);
break;
@@ -1037,7 +1097,7 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
char _old_name[old_dentry->d_name.len + 1];
char _new_name[new_dentry->d_name.len + 1];
- DPRINTK(KERN_DEBUG "ncp_rename: %s/%s to %s/%s\n",
+ DPRINTK("ncp_rename: %s/%s to %s/%s\n",
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
@@ -1067,7 +1127,7 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
#endif
switch (error) {
case 0x00:
- DPRINTK(KERN_DEBUG "ncp renamed %s -> %s.\n",
+ DPRINTK("ncp renamed %s -> %s.\n",
old_dentry->d_name.name,new_dentry->d_name.name);
/* d_move(old_dentry, new_dentry); */
break;
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index e39578d75..4a907a9b1 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -46,7 +46,7 @@ int ncp_make_open(struct inode *inode, int right)
goto out;
}
- DPRINTK(KERN_DEBUG "ncp_make_open: opened=%d, volume # %u, dir entry # %u\n",
+ DPRINTK("ncp_make_open: opened=%d, volume # %u, dir entry # %u\n",
NCP_FINFO(inode)->opened,
NCP_FINFO(inode)->volNumber,
NCP_FINFO(inode)->dirEntNum);
@@ -67,9 +67,7 @@ int ncp_make_open(struct inode *inode, int right)
NULL, NULL, OC_MODE_OPEN,
0, AR_READ, &finfo);
if (result) {
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_make_open: failed, result=%d\n", result);
-#endif
+ PPRINTK("ncp_make_open: failed, result=%d\n", result);
goto out_unlock;
}
/*
@@ -80,9 +78,7 @@ printk(KERN_DEBUG "ncp_make_open: failed, result=%d\n", result);
}
access = NCP_FINFO(inode)->access;
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_make_open: file open, access=%x\n", access);
-#endif
+ PPRINTK("ncp_make_open: file open, access=%x\n", access);
if (access == right || access == O_RDWR)
error = 0;
@@ -104,12 +100,12 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
void* freepage;
size_t freelen;
- DPRINTK(KERN_DEBUG "ncp_file_read: enter %s/%s\n",
+ DPRINTK("ncp_file_read: enter %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
error = -EINVAL;
if (inode == NULL) {
- DPRINTK(KERN_DEBUG "ncp_file_read: inode = NULL\n");
+ DPRINTK("ncp_file_read: inode = NULL\n");
goto out;
}
error = -EIO;
@@ -117,7 +113,7 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
goto out;
error = -EINVAL;
if (!S_ISREG(inode->i_mode)) {
- DPRINTK(KERN_DEBUG "ncp_file_read: read from non-file, mode %07o\n",
+ DPRINTK("ncp_file_read: read from non-file, mode %07o\n",
inode->i_mode);
goto out;
}
@@ -177,7 +173,7 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
inode->i_atime = CURRENT_TIME;
}
- DPRINTK(KERN_DEBUG "ncp_file_read: exit %s/%s\n",
+ DPRINTK("ncp_file_read: exit %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
out:
return already_read ? already_read : error;
@@ -194,17 +190,17 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
int errno;
void* bouncebuffer;
- DPRINTK(KERN_DEBUG "ncp_file_write: enter %s/%s\n",
+ DPRINTK("ncp_file_write: enter %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
if (inode == NULL) {
- DPRINTK(KERN_DEBUG "ncp_file_write: inode = NULL\n");
+ DPRINTK("ncp_file_write: inode = NULL\n");
return -EINVAL;
}
errno = -EIO;
if (!ncp_conn_valid(NCP_SERVER(inode)))
goto out;
if (!S_ISREG(inode->i_mode)) {
- DPRINTK(KERN_DEBUG "ncp_file_write: write to non-file, mode %07o\n",
+ DPRINTK("ncp_file_write: write to non-file, mode %07o\n",
inode->i_mode);
return -EINVAL;
}
@@ -260,7 +256,7 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
if (pos > inode->i_size) {
inode->i_size = pos;
}
- DPRINTK(KERN_DEBUG "ncp_file_write: exit %s/%s\n",
+ DPRINTK("ncp_file_write: exit %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
out:
return already_written ? already_written : errno;
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index e2d8a8a0f..ec2c1a4e4 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -72,10 +72,9 @@ void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
NCP_FINFO(inode)->server_file_handle = nwinfo->server_file_handle;
memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
sizeof(nwinfo->file_handle));
-#ifdef NCPFS_DEBUG_VERBOSE
-printk(KERN_DEBUG "ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
-nwinfo->i.entryName, NCP_FINFO(inode)->volNumber, NCP_FINFO(inode)->dirEntNum);
-#endif
+ DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
+ nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
+ NCP_FINFO(inode)->dirEntNum);
}
void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
@@ -123,12 +122,8 @@ void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
}
if (nwi->attributes & aRONLY) inode->i_mode &= ~0222;
}
- inode->i_blocks = 0;
- if ((inode->i_size)&&(inode->i_blksize)) {
- inode->i_blocks = (inode->i_size-1)/(inode->i_blksize)+1;
- }
+ inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
- /* TODO: times? I'm not sure... */
inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwinfo->i.modifyTime),
le16_to_cpu(nwinfo->i.modifyDate));
inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwinfo->i.creationTime),
@@ -163,8 +158,8 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
case aHIDDEN:
if (server->m.flags & NCP_MOUNT_SYMLINKS) {
- if ((inode->i_size >= NCP_MIN_SYMLINK_SIZE)
- && (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
+ if (/* (inode->i_size >= NCP_MIN_SYMLINK_SIZE)
+ && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
break;
}
@@ -188,19 +183,15 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
}
if (nwi->attributes & aRONLY) inode->i_mode &= ~0222;
- DDPRINTK(KERN_DEBUG "ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
+ DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
inode->i_nlink = 1;
inode->i_uid = server->m.uid;
inode->i_gid = server->m.gid;
- inode->i_blksize = NCP_BLOCK_SIZE;
inode->i_rdev = 0;
+ inode->i_blksize = NCP_BLOCK_SIZE;
- inode->i_blocks = 0;
- if ((inode->i_blksize != 0) && (inode->i_size != 0)) {
- inode->i_blocks =
- (inode->i_size - 1) / inode->i_blksize + 1;
- }
+ inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime),
le16_to_cpu(nwi->modifyDate));
@@ -255,7 +246,7 @@ static void
ncp_delete_inode(struct inode *inode)
{
if (S_ISDIR(inode->i_mode)) {
- DDPRINTK(KERN_DEBUG "ncp_delete_inode: put directory %ld\n", inode->i_ino);
+ DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino);
}
if (NCP_FINFO(inode)->opened && ncp_make_closed(inode) != 0) {
@@ -323,10 +314,11 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
server->m = *data;
/* Althought anything producing this is buggy, it happens
now because of PATH_MAX changes.. */
- if (server->m.time_out < 10) {
+ if (server->m.time_out < 1) {
server->m.time_out = 10;
printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
}
+ server->m.time_out = server->m.time_out * HZ / 100;
server->m.file_mode = (server->m.file_mode &
(S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFREG;
server->m.dir_mode = (server->m.dir_mode &
@@ -350,7 +342,7 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
ncp_unlock_server(server);
if (error < 0)
goto out_no_connect;
- DPRINTK(KERN_DEBUG "ncp_read_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
+ DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
#ifdef CONFIG_NCPFS_PACKET_SIGNING
if (ncp_negotiate_size_and_options(server, NCP_DEFAULT_BUFSIZE,
@@ -375,7 +367,7 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
if (ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE,
&(server->buffer_size)) != 0)
goto out_no_bufsize;
- DPRINTK(KERN_DEBUG "ncpfs: bufsize = %d\n", server->buffer_size);
+ DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
memset(&finfo, 0, sizeof(finfo));
finfo.i.attributes = aDIR;
@@ -402,7 +394,7 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
root_inode = ncp_iget(sb, &finfo);
if (!root_inode)
goto out_no_root;
- DPRINTK(KERN_DEBUG "ncp_read_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
+ DPRINTK("ncp_read_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
sb->s_root = d_alloc_root(root_inode);
if (!sb->s_root)
goto out_no_root;
@@ -650,7 +642,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
if ((attr->ia_valid & ATTR_SIZE) != 0) {
int written;
- DPRINTK(KERN_DEBUG "ncpfs: trying to change size to %ld\n",
+ DPRINTK("ncpfs: trying to change size to %ld\n",
attr->ia_size);
if ((result = ncp_make_open(inode, O_RDWR)) < 0) {
@@ -689,7 +681,7 @@ EXPORT_NO_SYMBOLS;
int init_module(void)
{
- DPRINTK(KERN_DEBUG "ncpfs: init_module called\n");
+ DPRINTK("ncpfs: init_module called\n");
#ifdef DEBUG_NCP_MALLOC
ncp_malloced = 0;
@@ -700,11 +692,11 @@ int init_module(void)
void cleanup_module(void)
{
- DPRINTK(KERN_DEBUG "ncpfs: cleanup_module called\n");
+ DPRINTK("ncpfs: cleanup_module called\n");
unregister_filesystem(&ncp_fs_type);
#ifdef DEBUG_NCP_MALLOC
- printk(KERN_DEBUG "ncp_malloced: %d\n", ncp_malloced);
- printk(KERN_DEBUG "ncp_current_malloced: %d\n", ncp_current_malloced);
+ PRINTK("ncp_malloced: %d\n", ncp_malloced);
+ PRINTK("ncp_current_malloced: %d\n", ncp_current_malloced);
#endif
}
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index ca2b534eb..05def9d6c 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -93,7 +93,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
else
result = server->reply_size;
ncp_unlock_server(server);
- DPRINTK(KERN_DEBUG "ncp_ioctl: copy %d bytes\n",
+ DPRINTK("ncp_ioctl: copy %d bytes\n",
result);
if (result >= 0)
if (copy_to_user(request.data, bouncebuffer, result))
@@ -124,7 +124,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
copy_from_user(&info, (struct ncp_fs_info *) arg, sizeof(info));
if (info.version != NCP_GET_FS_INFO_VERSION) {
- DPRINTK(KERN_DEBUG "info.version invalid: %d\n", info.version);
+ DPRINTK("info.version invalid: %d\n", info.version);
return -EINVAL;
}
/* TODO: info.addr = server->m.serv_addr; */
@@ -171,9 +171,9 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
sr.dirEntNum = NCP_FINFO(inode)->dirEntNum;
sr.namespace = server->name_space[sr.volNumber];
} else
- DPRINTK(KERN_DEBUG "ncpfs: s_root->d_inode==NULL\n");
+ DPRINTK("ncpfs: s_root->d_inode==NULL\n");
} else
- DPRINTK(KERN_DEBUG "ncpfs: s_root==NULL\n");
+ DPRINTK("ncpfs: s_root==NULL\n");
} else {
sr.volNumber = -1;
sr.namespace = 0;
@@ -221,9 +221,9 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
NCP_FINFO(inode)->dirEntNum = i.dirEntNum;
NCP_FINFO(inode)->DosDirNum = i.DosDirNum;
} else
- DPRINTK(KERN_DEBUG "ncpfs: s_root->d_inode==NULL\n");
+ DPRINTK("ncpfs: s_root->d_inode==NULL\n");
} else
- DPRINTK(KERN_DEBUG "ncpfs: s_root==NULL\n");
+ DPRINTK("ncpfs: s_root==NULL\n");
return 0;
}
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index 776e9366b..036e92e93 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -30,23 +30,25 @@ static inline int min(int a, int b)
/*
* Fill in the supplied page for mmap
*/
-static unsigned long ncp_file_mmap_nopage(struct vm_area_struct *area,
- unsigned long address, int no_share)
+static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area,
+ unsigned long address, int write_access)
{
struct file *file = area->vm_file;
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
- unsigned long page;
+ struct page* page;
+ unsigned long pg_addr;
unsigned int already_read;
unsigned int count;
int bufsize;
int pos;
- page = __get_free_page(GFP_KERNEL);
+ page = alloc_page(GFP_KERNEL);
if (!page)
return page;
+ pg_addr = page_address(page);
address &= PAGE_MASK;
- pos = address - area->vm_start + area->vm_offset;
+ pos = address - area->vm_start + (area->vm_pgoff << PAGE_SHIFT);
count = PAGE_SIZE;
if (address + PAGE_SIZE > area->vm_end) {
@@ -68,7 +70,7 @@ static unsigned long ncp_file_mmap_nopage(struct vm_area_struct *area,
if (ncp_read_kernel(NCP_SERVER(inode),
NCP_FINFO(inode)->file_handle,
pos, to_read,
- (char *) (page + already_read),
+ (char *) (pg_addr + already_read),
&read_this_time) != 0) {
read_this_time = 0;
}
@@ -83,7 +85,7 @@ static unsigned long ncp_file_mmap_nopage(struct vm_area_struct *area,
}
if (already_read < PAGE_SIZE)
- memset((char*)(page + already_read), 0,
+ memset((char*)(pg_addr + already_read), 0,
PAGE_SIZE - already_read);
return page;
}
@@ -107,7 +109,7 @@ int ncp_mmap(struct file *file, struct vm_area_struct *vma)
{
struct inode *inode = file->f_dentry->d_inode;
- DPRINTK(KERN_DEBUG "ncp_mmap: called\n");
+ DPRINTK("ncp_mmap: called\n");
if (!ncp_conn_valid(NCP_SERVER(inode))) {
return -EIO;
@@ -117,6 +119,11 @@ int ncp_mmap(struct file *file, struct vm_area_struct *vma)
return -EINVAL;
if (!inode->i_sb || !S_ISREG(inode->i_mode))
return -EACCES;
+ /* we do not support files bigger than 4GB... We eventually
+ supports just 4GB... */
+ if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff
+ > (1U << (32 - PAGE_SHIFT)))
+ return -EFBIG;
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
}
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
index 2881c74fa..5dbd0c55a 100644
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -17,10 +17,10 @@ static inline int min(int a, int b)
return a < b ? a : b;
}
-static void assert_server_locked(struct ncp_server *server)
+static inline void assert_server_locked(struct ncp_server *server)
{
if (server->lock == 0) {
- DPRINTK(KERN_DEBUG "ncpfs: server not locked!\n");
+ DPRINTK("ncpfs: server not locked!\n");
}
}
@@ -69,7 +69,7 @@ static void ncp_add_pstring(struct ncp_server *server, const char *s)
int len = strlen(s);
assert_server_locked(server);
if (len > 255) {
- DPRINTK(KERN_DEBUG "ncpfs: string too long: %s\n", s);
+ DPRINTK("ncpfs: string too long: %s\n", s);
len = 255;
}
ncp_add_byte(server, len);
@@ -77,7 +77,7 @@ static void ncp_add_pstring(struct ncp_server *server, const char *s)
return;
}
-static void ncp_init_request(struct ncp_server *server)
+static inline void ncp_init_request(struct ncp_server *server)
{
ncp_lock_server(server);
@@ -95,7 +95,7 @@ static void ncp_init_request_s(struct ncp_server *server, int subfunction)
server->has_subfunction = 1;
}
-static char *
+static inline char *
ncp_reply_data(struct ncp_server *server, int offset)
{
return &(server->packet[sizeof(struct ncp_reply_header) + offset]);
@@ -196,7 +196,7 @@ ncp_get_volume_info_with_number(struct ncp_server *server, int n,
result = -EIO;
len = ncp_reply_byte(server, 29);
if (len > NCP_VOLNAME_LEN) {
- DPRINTK(KERN_DEBUG "ncpfs: volume name too long: %d\n", len);
+ DPRINTK("ncpfs: volume name too long: %d\n", len);
goto out;
}
memcpy(&(target->volume_name), ncp_reply_data(server, 30), len);
@@ -229,11 +229,11 @@ ncp_make_closed(struct inode *inode)
int err;
NCP_FINFO(inode)->opened = 0;
err = ncp_close_file(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle);
-#ifdef NCPFS_PARANOIA
-if (!err)
-printk(KERN_DEBUG "ncp_make_closed: volnum=%d, dirent=%u, error=%d\n",
-NCP_FINFO(inode)->volNumber, NCP_FINFO(inode)->dirEntNum, err);
-#endif
+
+ if (!err)
+ PPRINTK("ncp_make_closed: volnum=%d, dirent=%u, error=%d\n",
+ NCP_FINFO(inode)->volNumber,
+ NCP_FINFO(inode)->dirEntNum, err);
return err;
}
@@ -350,7 +350,7 @@ ncp_get_known_namespace(struct ncp_server *server, __u8 volume)
namespace = ncp_reply_data(server, 2);
while (no_namespaces > 0) {
- DPRINTK(KERN_DEBUG "get_namespaces: found %d on %d\n", *namespace, volume);
+ DPRINTK("get_namespaces: found %d on %d\n", *namespace, volume);
#ifdef CONFIG_NCPFS_NFS_NS
if ((*namespace == NW_NS_NFS) && !(server->m.flags&NCP_MOUNT_NO_NFS))
@@ -387,7 +387,7 @@ ncp_ObtainSpecificDirBase(struct ncp_server *server,
ncp_add_byte(server, 6); /* subfunction */
ncp_add_byte(server, nsSrc);
ncp_add_byte(server, nsDst);
- ncp_add_word(server, 0x8006); /* get all */
+ ncp_add_word(server, htons(0x0680)); /* get all */
ncp_add_dword(server, RIM_ALL);
ncp_add_handle_path(server, vol_num, dir_base, 1, path);
@@ -436,7 +436,7 @@ ncp_lookup_volume(struct ncp_server *server, char *volname,
int result;
int volnum;
- DPRINTK(KERN_DEBUG "ncp_lookup_volume: looking up vol %s\n", volname);
+ DPRINTK("ncp_lookup_volume: looking up vol %s\n", volname);
ncp_init_request(server);
ncp_add_byte(server, 22); /* Subfunction: Generate dir handle */
@@ -462,7 +462,7 @@ ncp_lookup_volume(struct ncp_server *server, char *volname,
server->name_space[volnum] = ncp_get_known_namespace(server, volnum);
- DPRINTK(KERN_DEBUG "lookup_vol: namespace[%d] = %d\n",
+ DPRINTK("lookup_vol: namespace[%d] = %d\n",
volnum, server->name_space[volnum]);
target->nameLen = strlen(volname);
@@ -537,7 +537,7 @@ ncp_del_file_or_subdir2(struct ncp_server *server,
if (!inode) {
#if CONFIG_NCPFS_DEBUGDENTRY
- printk(KERN_DEBUG "ncpfs: ncpdel2: dentry->d_inode == NULL\n");
+ PRINTK("ncpfs: ncpdel2: dentry->d_inode == NULL\n");
#endif
return 0xFF; /* Any error */
}
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index f4cc6425b..92309db26 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -36,7 +36,8 @@
#define NCP_MIN_SYMLINK_SIZE 8
#define NCP_MAX_SYMLINK_SIZE 512
-#define NCP_BLOCK_SIZE 512
+#define NCP_BLOCK_SHIFT 9
+#define NCP_BLOCK_SIZE (1 << (NCP_BLOCK_SHIFT))
int ncp_negotiate_buffersize(struct ncp_server *, int, int *);
int ncp_negotiate_size_and_options(struct ncp_server *server, int size,
@@ -173,8 +174,8 @@ vol2io(struct ncp_server *server, char *name, int case_trans)
#endif /* CONFIG_NCPFS_NLS */
#define NCP_GET_AGE(dentry) (jiffies - (dentry)->d_time)
-#define NCP_MAX_AGE (server->dentry_ttl)
-#define NCP_TEST_AGE(server,dentry) (NCP_GET_AGE(dentry) < NCP_MAX_AGE)
+#define NCP_MAX_AGE(server) ((server)->dentry_ttl)
+#define NCP_TEST_AGE(server,dentry) (NCP_GET_AGE(dentry) < NCP_MAX_AGE(server))
static inline void
ncp_age_dentry(struct ncp_server* server, struct dentry* dentry)
@@ -188,21 +189,65 @@ ncp_new_dentry(struct dentry* dentry)
dentry->d_time = jiffies;
}
-#define NCP_FPOS_EMPTY 0 /* init value for fpos variables. */
+static inline void
+ncp_renew_dentries(struct dentry *parent)
+{
+ struct ncp_server *server = NCP_SERVER(parent->d_inode);
+ struct list_head *next = parent->d_subdirs.next;
+ struct dentry *dentry;
-struct ncp_cache_control {
- struct nw_search_sequence seq;
- int firstcache;
- int currentpos;
- int cachehead;
- int cachetail;
+ while (next != &parent->d_subdirs) {
+ dentry = list_entry(next, struct dentry, d_child);
+
+ if (dentry->d_fsdata == NULL)
+ ncp_age_dentry(server, dentry);
+ else
+ ncp_new_dentry(dentry);
+
+ next = next->next;
+ }
+}
+
+static inline void
+ncp_invalidate_dircache_entries(struct dentry *parent)
+{
+ struct ncp_server *server = NCP_SERVER(parent->d_inode);
+ struct list_head *next = parent->d_subdirs.next;
+ struct dentry *dentry;
+
+ while (next != &parent->d_subdirs) {
+ dentry = list_entry(next, struct dentry, d_child);
+ dentry->d_fsdata = NULL;
+ ncp_age_dentry(server, dentry);
+ next = next->next;
+ }
+}
+
+struct ncp_cache_head {
+ time_t mtime;
+ unsigned long time; /* cache age */
+ unsigned long end; /* last valid fpos in cache */
int eof;
};
-#define NCP_DIRCACHE_SIZE (PAGE_CACHE_SIZE-sizeof(struct ncp_cache_control))
-struct ncp_seq_cache {
- struct ncp_cache_control ctl;
- unsigned char cache[NCP_DIRCACHE_SIZE];
+#define NCP_DIRCACHE_SIZE ((int)(PAGE_CACHE_SIZE/sizeof(struct dentry *)))
+union ncp_dir_cache {
+ struct ncp_cache_head head;
+ struct dentry *dentry[NCP_DIRCACHE_SIZE];
+};
+
+#define NCP_FIRSTCACHE_SIZE ((int)((NCP_DIRCACHE_SIZE * \
+ sizeof(struct dentry *) - sizeof(struct ncp_cache_head)) / \
+ sizeof(struct dentry *)))
+
+#define NCP_DIRCACHE_START (NCP_DIRCACHE_SIZE - NCP_FIRSTCACHE_SIZE)
+
+struct ncp_cache_control {
+ struct ncp_cache_head head;
+ struct page *page;
+ union ncp_dir_cache *cache;
+ unsigned long fpos, ofs;
+ int filled, valid, idx;
};
#endif /* _NCPLIB_H */
diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c
index 2d43ec9ad..33a4293c4 100644
--- a/fs/ncpfs/sock.c
+++ b/fs/ncpfs/sock.c
@@ -144,7 +144,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size,
set_fs(get_ds());
for (n = 0, timeout = init_timeout;; n++, timeout <<= 1) {
/*
- DDPRINTK(KERN_DEBUG "ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X\n",
+ DDPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X\n",
htonl(server->m.serv_addr.sipx_network),
server->m.serv_addr.sipx_node[0],
server->m.serv_addr.sipx_node[1],
@@ -154,12 +154,12 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size,
server->m.serv_addr.sipx_node[5],
ntohs(server->m.serv_addr.sipx_port));
*/
- DDPRINTK(KERN_DEBUG "ncpfs: req.typ: %04X, con: %d, "
+ DDPRINTK("ncpfs: req.typ: %04X, con: %d, "
"seq: %d",
request.type,
(request.conn_high << 8) + request.conn_low,
request.sequence);
- DDPRINTK(KERN_DEBUG " func: %d\n",
+ DDPRINTK(" func: %d\n",
request.function);
result = _send(sock, (void *) start, size);
@@ -223,11 +223,11 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size,
MSG_PEEK | MSG_DONTWAIT);
if (result < 0) {
if (result == -EAGAIN) {
- DDPRINTK(KERN_DEBUG "ncp_rpc_call: bad select ready\n");
+ DDPRINTK("ncp_rpc_call: bad select ready\n");
goto re_select;
}
if (result == -ECONNREFUSED) {
- DPRINTK(KERN_WARNING "ncp_rpc_call: server playing coy\n");
+ DPRINTK("ncp_rpc_call: server playing coy\n");
goto re_select;
}
if (result != -ERESTARTSYS) {
@@ -239,7 +239,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size,
if ((result == sizeof(reply))
&& (reply.type == NCP_POSITIVE_ACK)) {
/* Throw away the packet */
- DPRINTK(KERN_DEBUG "ncp_rpc_call: got positive acknowledge\n");
+ DPRINTK("ncp_rpc_call: got positive acknowledge\n");
_recv(sock, (void *) &reply, sizeof(reply),
MSG_DONTWAIT);
n = 0;
@@ -247,7 +247,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size,
acknowledge_seen = 1;
goto re_select;
}
- DDPRINTK(KERN_DEBUG "ncpfs: rep.typ: %04X, con: %d, tsk: %d,"
+ DDPRINTK("ncpfs: rep.typ: %04X, con: %d, tsk: %d,"
"seq: %d\n",
reply.type,
(reply.conn_high << 8) + reply.conn_low,
@@ -271,7 +271,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size,
* a null buffer yet. */
_recv(sock, (void *) &reply, sizeof(reply), MSG_DONTWAIT);
- DPRINTK(KERN_WARNING "ncp_rpc_call: reply mismatch\n");
+ DPRINTK("ncp_rpc_call: reply mismatch\n");
goto re_select;
}
/*
@@ -321,7 +321,7 @@ static int ncp_do_request(struct ncp_server *server, int size,
#endif /* CONFIG_NCPFS_PACKET_SIGNING */
result = do_ncp_rpc_call(server, size, reply, max_reply_size);
- DDPRINTK(KERN_DEBUG "do_ncp_rpc_call returned %d\n", result);
+ DDPRINTK("do_ncp_rpc_call returned %d\n", result);
if (result < 0) {
/* There was a problem with I/O, so the connections is
@@ -363,7 +363,7 @@ int ncp_request2(struct ncp_server *server, int function,
result = ncp_do_request(server, request_size + sizeof(*h), reply, size);
if (result < 0) {
- DPRINTK(KERN_WARNING "ncp_request_error: %d\n", result);
+ DPRINTK("ncp_request_error: %d\n", result);
goto out;
}
server->completion = reply->completion_code;
@@ -373,10 +373,8 @@ int ncp_request2(struct ncp_server *server, int function,
result = reply->completion_code;
-#ifdef NCPFS_PARANOIA
-if (result != 0)
-printk(KERN_DEBUG "ncp_request: completion code=%x\n", result);
-#endif
+ if (result != 0)
+ PPRINTK("ncp_request: completion code=%x\n", result);
out:
return result;
}
@@ -428,7 +426,7 @@ void ncp_lock_server(struct ncp_server *server)
#if 0
/* For testing, only 1 process */
if (server->lock != 0) {
- DPRINTK(KERN_WARNING "ncpfs: server locked!!!\n");
+ DPRINTK("ncpfs: server locked!!!\n");
}
#endif
down(&server->sem);
diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
index 578b2b985..81151959a 100644
--- a/fs/ncpfs/symlink.c
+++ b/fs/ncpfs/symlink.c
@@ -80,7 +80,7 @@ static struct dentry *ncp_follow_link(struct dentry *dentry,
char *link;
#ifdef DEBUG
- printk("ncp_follow_link(dentry=%p,base=%p,follow=%u)\n",dentry,base,follow);
+ PRINTK("ncp_follow_link(dentry=%p,base=%p,follow=%u)\n",dentry,base,follow);
#endif
if(!S_ISLNK(inode->i_mode)) {
@@ -131,7 +131,7 @@ static int ncp_readlink(struct dentry * dentry, char * buffer, int buflen)
int length,error;
#ifdef DEBUG
- printk("ncp_readlink(dentry=%p,buffer=%p,buflen=%d)\n",dentry,buffer,buflen);
+ PRINTK("ncp_readlink(dentry=%p,buffer=%p,buflen=%d)\n",dentry,buffer,buflen);
#endif
if(!S_ISLNK(inode->i_mode))
@@ -173,7 +173,7 @@ int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
char *link;
#ifdef DEBUG
- printk("ncp_symlink(dir=%p,dentry=%p,symname=%s)\n",dir,dentry,symname);
+ PRINTK("ncp_symlink(dir=%p,dentry=%p,symname=%s)\n",dir,dentry,symname);
#endif
if (!(NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS))
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 651b1152c..149077fae 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1200,12 +1200,12 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *old_inode = old_dentry->d_inode;
struct inode *new_inode = new_dentry->d_inode;
struct dentry *dentry = NULL;
- int error, rehash = 0, update = 1;
+ int error, rehash = 0;
dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n",
- old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
- new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
- new_dentry->d_count);
+ old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
+ new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
+ new_dentry->d_count);
/*
* First check whether the target is busy ... we can't
@@ -1238,21 +1238,16 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
/* dentry still busy? */
if (new_dentry->d_count > 1) {
#ifdef NFS_PARANOIA
-printk("nfs_rename: target %s/%s busy, d_count=%d\n",
-new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
+ printk("nfs_rename: target %s/%s busy, d_count=%d\n",
+ new_dentry->d_parent->d_name.name,
+ new_dentry->d_name.name,
+ new_dentry->d_count);
#endif
goto out;
}
}
/*
- * Check for within-directory rename ... no complications.
- */
- if (new_dir == old_dir)
- goto do_rename;
- /*
- * Cross-directory move ...
- *
* ... prune child dentries and writebacks if needed.
*/
if (old_dentry->d_count > 1) {
@@ -1260,40 +1255,26 @@ new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
shrink_dcache_parent(old_dentry);
}
- /*
- * Now check the use counts ... we can't safely do the
- * rename unless we can drop the dentries first.
- */
- if (old_dentry->d_count > 1) {
-#ifdef NFS_PARANOIA
-printk("nfs_rename: old dentry %s/%s busy, d_count=%d\n",
-old_dentry->d_parent->d_name.name,old_dentry->d_name.name,old_dentry->d_count);
-#endif
- goto out;
- }
if (new_dentry->d_count > 1 && new_inode) {
#ifdef NFS_PARANOIA
-printk("nfs_rename: new dentry %s/%s busy, d_count=%d\n",
-new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
+ printk("nfs_rename: new dentry %s/%s busy, d_count=%d\n",
+ new_dentry->d_parent->d_name.name,
+ new_dentry->d_name.name,
+ new_dentry->d_count);
#endif
goto out;
}
- d_drop(old_dentry);
- update = 0;
-
-do_rename:
/*
* To prevent any new references to the target during the rename,
* we unhash the dentry and free the inode in advance.
*/
if (!list_empty(&new_dentry->d_hash)) {
d_drop(new_dentry);
- rehash = update;
+ rehash = 1;
}
- if (new_inode) {
+ if (new_inode)
d_delete(new_dentry);
- }
invalidate_inode_pages(new_dir);
nfs_flush_dircache(new_dir);
@@ -1302,13 +1283,14 @@ do_rename:
error = nfs_proc_rename(NFS_DSERVER(old_dentry),
NFS_FH(old_dentry->d_parent), old_dentry->d_name.name,
NFS_FH(new_dentry->d_parent), new_dentry->d_name.name);
- if (!error && !S_ISDIR(old_inode->i_mode)) {
- /* Update the dcache if needed */
- if (rehash)
- d_add(new_dentry, NULL);
- if (update)
- d_move(old_dentry, new_dentry);
- }
+
+ NFS_CACHEINV(old_dir);
+ NFS_CACHEINV(new_dir);
+ /* Update the dcache if needed */
+ if (rehash)
+ d_add(new_dentry, NULL);
+ if (!error && !S_ISDIR(old_inode->i_mode))
+ d_move(old_dentry, new_dentry);
out:
/* new dentry created? */
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index ab1e51485..00b310e06 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -680,7 +680,7 @@ printk("nfs_notify_change: revalidate failed, error=%d\n", error);
*/
if (attr->ia_valid & ATTR_SIZE) {
if (attr->ia_size != fattr.size)
- printk("nfs_notify_change: attr=%ld, fattr=%d??\n",
+ printk("nfs_notify_change: attr=%Ld, fattr=%d??\n",
attr->ia_size, fattr.size);
inode->i_size = attr->ia_size;
inode->i_mtime = fattr.mtime.seconds;
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
index 3ecb9bfa6..f74984de2 100644
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -119,7 +119,7 @@ static struct rpc_procinfo mnt_procedures[2] = {
{ "mnt_mount",
(kxdrproc_t) xdr_encode_dirpath,
(kxdrproc_t) xdr_decode_fhstatus,
- MNT_dirpath_sz, MNT_fhstatus_sz },
+ MNT_dirpath_sz << 2, 0 },
};
static struct rpc_version mnt_version1 = {
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 6ef7b9282..beed6ec1e 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -679,7 +679,7 @@ nfs_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
static struct proc_dir_entry proc_nfsclnt = {
0, 3, "nfs",
S_IFREG | S_IRUGO, 1, 0, 0,
- 6, &proc_net_inode_operations,
+ 6, NULL,
nfs_get_info
};
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index a85ef5e74..6b2e3d73a 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -70,7 +70,7 @@ static int
nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
{
struct nfs_rreq rqst;
- unsigned long offset = page->offset;
+ unsigned long offset = page->index << PAGE_CACHE_SHIFT;
char *buffer = (char *) page_address(page);
int rsize = NFS_SERVER(inode)->rsize;
int result, refresh = 0;
@@ -179,7 +179,7 @@ nfs_readpage_async(struct dentry *dentry, struct inode *inode,
/* Initialize request */
/* N.B. Will the dentry remain valid for life of request? */
- nfs_readreq_setup(req, NFS_FH(dentry), page->offset,
+ nfs_readreq_setup(req, NFS_FH(dentry), page->index << PAGE_CACHE_SHIFT,
(void *) address, PAGE_SIZE);
req->ra_inode = inode;
req->ra_page = page; /* count has been incremented by caller */
@@ -224,8 +224,8 @@ nfs_readpage(struct file *file, struct page *page)
int error;
lock_kernel();
- dprintk("NFS: nfs_readpage (%p %ld@%ld)\n",
- page, PAGE_SIZE, page->offset);
+ dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
+ page, PAGE_SIZE, page->index);
get_page(page);
/*
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 561e8450c..abc048dc2 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -95,12 +95,12 @@ nfs_writepage_sync(struct dentry *dentry, struct inode *inode,
struct nfs_fattr fattr;
lock_kernel();
- dprintk("NFS: nfs_writepage_sync(%s/%s %d@%ld)\n",
+ dprintk("NFS: nfs_writepage_sync(%s/%s %d@%lu/%ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- count, page->offset + offset);
+ count, page->index, offset);
buffer = (u8 *) page_address(page) + offset;
- offset += page->offset;
+ offset += page->index << PAGE_CACHE_SHIFT;
do {
if (count < wsize && !IS_SWAPFILE(inode))
@@ -287,7 +287,7 @@ create_write_request(struct file * file, struct page *page, unsigned int offset,
dprintk("NFS: create_write_request(%s/%s, %ld+%d)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- page->offset + offset, bytes);
+ (page->index << PAGE_CACHE_SHIFT) + offset, bytes);
/* FIXME: Enforce hard limit on number of concurrent writes? */
wreq = kmem_cache_alloc(nfs_wreq_cachep, SLAB_KERNEL);
@@ -435,7 +435,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
dprintk("NFS: nfs_updatepage(%s/%s %d@%ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- count, page->offset+offset);
+ count, (page->index << PAGE_CACHE_SHIFT) +offset);
/*
* Try to find a corresponding request on the writeback queue.
@@ -620,7 +620,7 @@ nfs_wback_begin(struct rpc_task *task)
/* Setup the task struct for a writeback call */
req->wb_flags |= NFS_WRITE_INPROGRESS;
req->wb_args.fh = NFS_FH(dentry);
- req->wb_args.offset = page->offset + req->wb_offset;
+ req->wb_args.offset = (page->index << PAGE_CACHE_SHIFT) + req->wb_offset;
req->wb_args.count = req->wb_bytes;
req->wb_args.buffer = (void *) (page_address(page) + req->wb_offset);
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 4ec7b691b..8c575db4e 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -57,13 +57,9 @@ int exp_procfs_exports(char *buffer, char **start, off_t offset,
void proc_export_init(void)
{
- struct proc_dir_entry *nfs_export_ent = NULL;
-
- if (!(nfs_export_ent = create_proc_entry("fs/nfs", S_IFDIR, 0)))
- return;
- if (!(nfs_export_ent = create_proc_entry("fs/nfs/exports", 0, 0)))
+ if (!create_proc_entry("fs/nfs", S_IFDIR, 0))
return;
- nfs_export_ent->read_proc = exp_procfs_exports;
+ create_proc_read_entry("fs/nfs/exports", 0, 0, exp_procfs_exports,NULL);
}
@@ -261,21 +257,6 @@ MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
extern int (*do_nfsservctl)(int, void *, void *);
/*
- * This is called as the fill_inode function when an inode
- * is going into (fill = 1) or out of service (fill = 0).
- *
- * We use it here to make sure the module can't be unloaded
- * while a /proc inode is in use.
- */
-void nfsd_modcount(struct inode *inode, int fill)
-{
- if (fill)
- MOD_INC_USE_COUNT;
- else
- MOD_DEC_USE_COUNT;
-}
-
-/*
* Initialize the module
*/
int
@@ -299,7 +280,6 @@ cleanup_module(void)
do_nfsservctl = NULL;
nfsd_export_shutdown();
nfsd_cache_shutdown();
- nfsd_fh_free();
remove_proc_entry("fs/nfs/exports", NULL);
remove_proc_entry("fs/nfs", NULL);
nfsd_stat_shutdown();
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 5f8e90a0e..42ad50fe9 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -279,6 +279,7 @@ find_fh_dentry(struct super_block *sb, struct knfs_fh *fh, int needpath)
/* It's a directory, or we are required to confirm the file's
* location in the tree.
*/
+ dprintk("nfs_fh: need to look harder for %d/%d\n",sb->s_dev,fh->fh_ino);
found = 0;
if (!S_ISDIR(result->d_inode->i_mode)) {
if (fh->fh_dirino == 0)
@@ -381,60 +382,69 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
fh->fh_ino,
fh->fh_dirino);
- /*
- * Security: Check that the fh is internally consistant (from <gam3@acm.org>)
- */
- if (fh->fh_dev != fh->fh_xdev) {
- printk("fh_verify: Security: export on other device (%s, %s).\n",
- kdevname(fh->fh_dev), kdevname(fh->fh_xdev));
- error = nfserr_stale;
- nfsdstats.fh_stale++;
- goto out;
- }
+ if (!fhp->fh_dverified) {
+ /*
+ * Security: Check that the fh is internally consistant (from <gam3@acm.org>)
+ */
+ if (fh->fh_dev != fh->fh_xdev) {
+ printk("fh_verify: Security: export on other device (%s, %s).\n",
+ kdevname(fh->fh_dev), kdevname(fh->fh_xdev));
+ error = nfserr_stale;
+ nfsdstats.fh_stale++;
+ goto out;
+ }
- /*
- * Look up the export entry.
- */
- error = nfserr_stale;
- exp = exp_get(rqstp->rq_client,
- u32_to_kdev_t(fh->fh_xdev),
- u32_to_ino_t(fh->fh_xino));
- if (!exp) {
- /* export entry revoked */
- nfsdstats.fh_stale++;
- goto out;
- }
+ /*
+ * Look up the export entry.
+ */
+ error = nfserr_stale;
+ exp = exp_get(rqstp->rq_client,
+ u32_to_kdev_t(fh->fh_xdev),
+ u32_to_ino_t(fh->fh_xino));
+ if (!exp) {
+ /* export entry revoked */
+ nfsdstats.fh_stale++;
+ goto out;
+ }
- /* Check if the request originated from a secure port. */
- error = nfserr_perm;
- if (!rqstp->rq_secure && EX_SECURE(exp)) {
- printk(KERN_WARNING
- "nfsd: request from insecure port (%08lx:%d)!\n",
- ntohl(rqstp->rq_addr.sin_addr.s_addr),
- ntohs(rqstp->rq_addr.sin_port));
- goto out;
- }
+ /* Check if the request originated from a secure port. */
+ error = nfserr_perm;
+ if (!rqstp->rq_secure && EX_SECURE(exp)) {
+ printk(KERN_WARNING
+ "nfsd: request from insecure port (%08lx:%d)!\n",
+ ntohl(rqstp->rq_addr.sin_addr.s_addr),
+ ntohs(rqstp->rq_addr.sin_port));
+ goto out;
+ }
- /* Set user creds if we haven't done so already. */
- nfsd_setuser(rqstp, exp);
+ /* Set user creds if we haven't done so already. */
+ nfsd_setuser(rqstp, exp);
- /*
- * Look up the dentry using the NFS file handle.
- */
+ /*
+ * Look up the dentry using the NFS file handle.
+ */
- dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
- fh,
- !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
+ dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
+ fh,
+ !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
- if (IS_ERR(dentry)) {
- error = nfserrno(-PTR_ERR(dentry));
- goto out;
- }
+ if (IS_ERR(dentry)) {
+ error = nfserrno(-PTR_ERR(dentry));
+ goto out;
+ }
- fhp->fh_dentry = dentry;
- fhp->fh_export = exp;
- fhp->fh_dverified = 1;
- nfsd_nr_verified++;
+ fhp->fh_dentry = dentry;
+ fhp->fh_export = exp;
+ fhp->fh_dverified = 1;
+ nfsd_nr_verified++;
+ } else {
+ /* just rechecking permissions
+ * (e.g. nfsproc_create calls fh_verify, then nfsd_create does as well)
+ */
+ dprintk("nfsd: fh_verify - just checking\n");
+ dentry = fhp->fh_dentry;
+ exp = fhp->fh_export;
+ }
inode = dentry->d_inode;
diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c
index accd0aadc..7e7eba9a9 100644
--- a/fs/nfsd/stats.c
+++ b/fs/nfsd/stats.c
@@ -17,6 +17,7 @@
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <linux/module.h>
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/stats.h>
@@ -77,9 +78,7 @@ nfsd_stat_init(void)
if ((ent = svc_proc_register(&nfsd_svcstats)) != 0) {
ent->read_proc = nfsd_proc_read;
-#ifdef MODULE
- ent->fill_inode = nfsd_modcount;
-#endif
+ ent->owner = THIS_MODULE;
}
}
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index bc849dd8e..398d2ebae 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -657,12 +657,9 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (!flen)
goto out;
- /* from mkdir it won't be verified, from create it will */
- if (!fhp->fh_dverified) {
- err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
- if (err)
- goto out;
- }
+ err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
+ if (err)
+ goto out;
dentry = fhp->fh_dentry;
dirp = dentry->d_inode;
diff --git a/fs/open.c b/fs/open.c
index 3caaa53ce..8c8d5698d 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -707,7 +707,7 @@ repeat:
/* Do we need to expand the fdset array? */
if (fd >= current->files->max_fdset) {
- error = expand_fdset(files, 0);
+ error = expand_fdset(files, fd);
if (!error) {
error = -EMFILE;
goto repeat;
@@ -719,7 +719,7 @@ repeat:
* Check whether we need to expand the fd array.
*/
if (fd >= files->max_fds) {
- error = expand_fd_array(files, 0);
+ error = expand_fd_array(files, fd);
if (!error) {
error = -EMFILE;
goto repeat;
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index 8a5286fa5..8ff6cd522 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -8,8 +8,8 @@
# Note 2! The CFLAGS definitions are now in the main makefile.
O_TARGET := proc.o
-O_OBJS := inode.o root.o base.o generic.o mem.o link.o fd.o array.o \
- kmsg.o scsi.o proc_tty.o sysvipc.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
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 249abd8cd..181cc4e62 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -46,6 +46,10 @@
*
* Gerhard Wichert : added BIGMEM support
* Siemens AG <Gerhard.Wichert@pdb.siemens.de>
+ *
+ * Al Viro & Jeff Garzik : moved most of the thing into base.c and
+ * : proc_misc.c. The rest may eventually go into
+ * : base.c too.
*/
#include <linux/types.h>
@@ -54,8 +58,6 @@
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/tty.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
#include <linux/string.h>
#include <linux/mman.h>
#include <linux/proc_fs.h>
@@ -67,663 +69,12 @@
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/signal.h>
+#include <linux/highmem.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
-
-#define LOAD_INT(x) ((x) >> FSHIFT)
-#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
-
-#ifdef CONFIG_DEBUG_MALLOC
-int get_malloc(char * buffer);
-#endif
-
-
-static int open_kcore(struct inode * inode, struct file * filp)
-{
- return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
-}
-
-static ssize_t read_core(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- unsigned long p = *ppos, memsize;
- ssize_t read;
- ssize_t count1;
- char * pnt;
- struct user dump;
-#if defined (__i386__) || defined (__mc68000__)
-# define FIRST_MAPPED PAGE_SIZE /* we don't have page 0 mapped on x86.. */
-#else
-# define FIRST_MAPPED 0
-#endif
-
- memset(&dump, 0, sizeof(struct user));
- dump.magic = CMAGIC;
- dump.u_dsize = max_mapnr;
-#if defined (__i386__)
- dump.start_code = PAGE_OFFSET;
-#endif
-#ifdef __alpha__
- dump.start_data = PAGE_OFFSET;
-#endif
-
- memsize = (max_mapnr + 1) << PAGE_SHIFT;
- if (p >= memsize)
- return 0;
- if (count > memsize - p)
- count = memsize - p;
- read = 0;
-
- if (p < sizeof(struct user) && count > 0) {
- count1 = count;
- if (p + count1 > sizeof(struct user))
- count1 = sizeof(struct user)-p;
- pnt = (char *) &dump + p;
- copy_to_user(buf,(void *) pnt, count1);
- buf += count1;
- p += count1;
- count -= count1;
- read += count1;
- }
-
- if (count > 0 && p < PAGE_SIZE + FIRST_MAPPED) {
- count1 = PAGE_SIZE + FIRST_MAPPED - p;
- if (count1 > count)
- count1 = count;
- clear_user(buf, count1);
- buf += count1;
- p += count1;
- count -= count1;
- read += count1;
- }
- if (count > 0) {
- copy_to_user(buf, (void *) (PAGE_OFFSET+p-PAGE_SIZE), count);
- read += count;
- }
- *ppos += read;
- return read;
-}
-
-static struct file_operations proc_kcore_operations = {
- NULL, /* lseek */
- read_core,
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- open_kcore
-};
-
-struct inode_operations proc_kcore_inode_operations = {
- &proc_kcore_operations,
-};
-
-/*
- * This function accesses profiling information. The returned data is
- * binary: the sampling step and the actual contents of the profile
- * buffer. Use of the program readprofile is recommended in order to
- * get meaningful info out of these data.
- */
-static ssize_t read_profile(struct file *file, char *buf,
- size_t count, loff_t *ppos)
-{
- unsigned long p = *ppos;
- ssize_t read;
- char * pnt;
- unsigned int sample_step = 1 << prof_shift;
-
- if (p >= (prof_len+1)*sizeof(unsigned int))
- return 0;
- if (count > (prof_len+1)*sizeof(unsigned int) - p)
- count = (prof_len+1)*sizeof(unsigned int) - p;
- read = 0;
-
- while (p < sizeof(unsigned int) && count > 0) {
- put_user(*((char *)(&sample_step)+p),buf);
- buf++; p++; count--; read++;
- }
- pnt = (char *)prof_buffer + p - sizeof(unsigned int);
- copy_to_user(buf,(void *)pnt,count);
- read += count;
- *ppos += read;
- return read;
-}
-
-/*
- * Writing to /proc/profile resets the counters
- *
- * Writing a 'profiling multiplier' value into it also re-sets the profiling
- * interrupt frequency, on architectures that support this.
- */
-static ssize_t write_profile(struct file * file, const char * buf,
- size_t count, loff_t *ppos)
-{
-#ifdef __SMP__
- extern int setup_profiling_timer (unsigned int multiplier);
-
- if (count==sizeof(int)) {
- unsigned int multiplier;
-
- if (copy_from_user(&multiplier, buf, sizeof(int)))
- return -EFAULT;
-
- if (setup_profiling_timer(multiplier))
- return -EINVAL;
- }
-#endif
-
- memset(prof_buffer, 0, prof_len * sizeof(*prof_buffer));
- return count;
-}
-
-static struct file_operations proc_profile_operations = {
- NULL, /* lseek */
- read_profile,
- write_profile,
-};
-
-struct inode_operations proc_profile_inode_operations = {
- &proc_profile_operations,
-};
-
-
-static int get_loadavg(char * buffer)
-{
- int a, b, c;
-
- a = avenrun[0] + (FIXED_1/200);
- b = avenrun[1] + (FIXED_1/200);
- c = avenrun[2] + (FIXED_1/200);
- return sprintf(buffer,"%d.%02d %d.%02d %d.%02d %d/%d %d\n",
- LOAD_INT(a), LOAD_FRAC(a),
- LOAD_INT(b), LOAD_FRAC(b),
- LOAD_INT(c), LOAD_FRAC(c),
- nr_running, nr_threads, last_pid);
-}
-
-static int get_kstat(char * buffer)
-{
- int i, len;
- unsigned sum = 0;
- extern unsigned long total_forks;
- unsigned long jif = HZ_TO_STD(jiffies);
-
- for (i = 0 ; i < NR_IRQS ; i++)
- sum += kstat_irqs(i);
-
-#ifdef __SMP__
- len = sprintf(buffer,
- "cpu %u %u %u %lu\n",
- kstat.cpu_user,
- kstat.cpu_nice,
- kstat.cpu_system,
- jif*smp_num_cpus - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
- for (i = 0 ; i < smp_num_cpus; i++)
- len += sprintf(buffer + len, "cpu%d %u %u %u %lu\n",
- i,
- kstat.per_cpu_user[cpu_logical_map(i)],
- kstat.per_cpu_nice[cpu_logical_map(i)],
- kstat.per_cpu_system[cpu_logical_map(i)],
- jif - ( kstat.per_cpu_user[cpu_logical_map(i)] \
- + kstat.per_cpu_nice[cpu_logical_map(i)] \
- + kstat.per_cpu_system[cpu_logical_map(i)]));
- len += sprintf(buffer + len,
- "disk %u %u %u %u\n"
- "disk_rio %u %u %u %u\n"
- "disk_wio %u %u %u %u\n"
- "disk_rblk %u %u %u %u\n"
- "disk_wblk %u %u %u %u\n"
- "page %u %u\n"
- "swap %u %u\n"
- "intr %u",
-#else
- len = sprintf(buffer,
- "cpu %u %u %u %lu\n"
- "disk %u %u %u %u\n"
- "disk_rio %u %u %u %u\n"
- "disk_wio %u %u %u %u\n"
- "disk_rblk %u %u %u %u\n"
- "disk_wblk %u %u %u %u\n"
- "page %u %u\n"
- "swap %u %u\n"
- "intr %u",
- HZ_TO_STD(kstat.cpu_user),
- HZ_TO_STD(kstat.cpu_nice),
- HZ_TO_STD(kstat.cpu_system),
- jif*smp_num_cpus - HZ_TO_STD(kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
-#endif
- kstat.dk_drive[0], kstat.dk_drive[1],
- kstat.dk_drive[2], kstat.dk_drive[3],
- kstat.dk_drive_rio[0], kstat.dk_drive_rio[1],
- kstat.dk_drive_rio[2], kstat.dk_drive_rio[3],
- kstat.dk_drive_wio[0], kstat.dk_drive_wio[1],
- kstat.dk_drive_wio[2], kstat.dk_drive_wio[3],
- kstat.dk_drive_rblk[0], kstat.dk_drive_rblk[1],
- kstat.dk_drive_rblk[2], kstat.dk_drive_rblk[3],
- kstat.dk_drive_wblk[0], kstat.dk_drive_wblk[1],
- kstat.dk_drive_wblk[2], kstat.dk_drive_wblk[3],
- kstat.pgpgin,
- kstat.pgpgout,
- kstat.pswpin,
- kstat.pswpout,
- sum);
- for (i = 0 ; i < NR_IRQS ; i++)
- len += sprintf(buffer + len, " %u", kstat_irqs(i));
- len += sprintf(buffer + len,
- "\nctxt %u\n"
- "btime %lu\n"
- "processes %lu\n",
- kstat.context_swtch,
- xtime.tv_sec - jif / HZ,
- total_forks);
- return len;
-}
-
-
-static int get_uptime(char * buffer)
-{
- unsigned long uptime;
- unsigned long idle;
-
- uptime = jiffies;
- idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
-
- /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
- that would overflow about every five days at HZ == 100.
- Therefore the identity a = (a / b) * b + a % b is used so that it is
- calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
- The part in front of the '+' always evaluates as 0 (mod 100). All divisions
- in the above formulas are truncating. For HZ being a power of 10, the
- calculations simplify to the version in the #else part (if the printf
- format is adapted to the same number of digits as zeroes in HZ.
- */
-#if HZ!=100
- return sprintf(buffer,"%lu.%02lu %lu.%02lu\n",
- uptime / HZ,
- (((uptime % HZ) * 100) / HZ) % 100,
- idle / HZ,
- (((idle % HZ) * 100) / HZ) % 100);
-#else
- return sprintf(buffer,"%lu.%02lu %lu.%02lu\n",
- uptime / HZ,
- uptime % HZ,
- idle / HZ,
- idle % HZ);
-#endif
-}
-
-static int get_meminfo(char * buffer)
-{
- struct sysinfo i;
- int len;
-
-/*
- * display in kilobytes.
- */
-#define K(x) ((x) << (PAGE_SHIFT - 10))
-
- si_meminfo(&i);
- si_swapinfo(&i);
- len = sprintf(buffer, " total: used: free: shared: buffers: cached:\n"
- "Mem: %8lu %8lu %8lu %8lu %8lu %8u\n"
- "Swap: %8lu %8lu %8lu\n",
- K(i.totalram), K(i.totalram-i.freeram), K(i.freeram),
- K(i.sharedram), K(i.bufferram),
- K(atomic_read(&page_cache_size)), K(i.totalswap),
- K(i.totalswap-i.freeswap), K(i.freeswap));
- /*
- * Tagged format, for easy grepping and expansion.
- * The above will go away eventually, once the tools
- * have been updated.
- */
- return len + sprintf(buffer+len,
- "MemTotal: %8lu kB\n"
- "MemFree: %8lu kB\n"
- "MemShared: %8lu kB\n"
- "Buffers: %8lu kB\n"
- "Cached: %8u kB\n"
- "HighTotal: %8lu kB\n"
- "HighFree: %8lu kB\n"
- "SwapTotal: %8lu kB\n"
- "SwapFree: %8lu kB\n",
- K(i.totalram),
- K(i.freeram),
- K(i.sharedram),
- K(i.bufferram),
- K(atomic_read(&page_cache_size)),
- K(i.totalhigh),
- K(i.freehigh),
- K(i.totalswap),
- K(i.freeswap));
-#undef K
-}
-
-static int get_version(char * buffer)
-{
- extern char *linux_banner;
-
- strcpy(buffer, linux_banner);
- return strlen(buffer);
-}
-
-static int get_cmdline(char * buffer)
-{
- extern char saved_command_line[];
-
- return sprintf(buffer, "%s\n", saved_command_line);
-}
-
-static struct page * get_phys_addr(struct mm_struct * mm, unsigned long ptr)
-{
- pgd_t *pgd;
- pmd_t *pmd;
- pte_t pte;
-
- if (ptr >= TASK_SIZE)
- return 0;
- pgd = pgd_offset(mm,ptr);
- if (pgd_none(*pgd))
- return 0;
- if (pgd_bad(*pgd)) {
- pgd_ERROR(*pgd);
- pgd_clear(pgd);
- return 0;
- }
- pmd = pmd_offset(pgd,ptr);
- if (pmd_none(*pmd))
- return 0;
- if (pmd_bad(*pmd)) {
- pmd_ERROR(*pmd);
- pmd_clear(pmd);
- return 0;
- }
- pte = *pte_offset(pmd,ptr);
- if (!pte_present(pte))
- return 0;
- return pte_page(pte);
-}
-
-static int get_array(struct mm_struct *mm, unsigned long start, unsigned long end, char * buffer)
-{
- struct page *page;
- unsigned long kaddr;
- int size = 0, result = 0;
- char c;
-
- if (start >= end)
- return result;
- for (;;) {
- page = get_phys_addr(mm, start);
- if (!page)
- return result;
- kaddr = kmap(page, KM_READ) + (start & ~PAGE_MASK);
- do {
- c = *(char *) kaddr;
- if (!c)
- result = size;
- if (size < PAGE_SIZE)
- buffer[size++] = c;
- else {
- kunmap(kaddr, KM_READ);
- return result;
- }
- kaddr++;
- start++;
- if (!c && start >= end) {
- kunmap(kaddr, KM_READ);
- return result;
- }
- } while (kaddr & ~PAGE_MASK);
- kunmap(kaddr, KM_READ);
- }
- return result;
-}
-
-static struct mm_struct *get_mm(int pid)
-{
- struct task_struct *p;
- struct mm_struct *mm = NULL;
-
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (p)
- mm = p->mm;
- if (mm)
- atomic_inc(&mm->mm_users);
- read_unlock(&tasklist_lock);
- return mm;
-}
-
-
-static int get_env(int pid, char * buffer)
-{
- struct mm_struct *mm = get_mm(pid);
- int res = 0;
- if (mm) {
- res = get_array(mm, mm->env_start, mm->env_end, buffer);
- mmput(mm);
- }
- return res;
-}
-
-static int get_arg(int pid, char * buffer)
-{
- struct mm_struct *mm = get_mm(pid);
- int res = 0;
- if (mm) {
- res = get_array(mm, mm->arg_start, mm->arg_end, buffer);
- mmput(mm);
- }
- return res;
-}
-
-/*
- * These bracket the sleeping functions..
- */
-extern void scheduling_functions_start_here(void);
-extern void scheduling_functions_end_here(void);
-#define first_sched ((unsigned long) scheduling_functions_start_here)
-#define last_sched ((unsigned long) scheduling_functions_end_here)
-
-static unsigned long get_wchan(struct task_struct *p)
-{
- if (!p || p == current || p->state == TASK_RUNNING)
- return 0;
-#if defined(__i386__)
- {
- unsigned long ebp, esp, eip;
- unsigned long stack_page;
- int count = 0;
-
- stack_page = (unsigned long)p;
- esp = p->thread.esp;
- if (!stack_page || esp < stack_page || esp > 8188+stack_page)
- return 0;
- /* include/asm-i386/system.h:switch_to() pushes ebp last. */
- ebp = *(unsigned long *) esp;
- do {
- if (ebp < stack_page || ebp > 8184+stack_page)
- return 0;
- eip = *(unsigned long *) (ebp+4);
- if (eip < first_sched || eip >= last_sched)
- return eip;
- ebp = *(unsigned long *) ebp;
- } while (count++ < 16);
- }
-#elif defined(__alpha__)
- /*
- * This one depends on the frame size of schedule(). Do a
- * "disass schedule" in gdb to find the frame size. Also, the
- * code assumes that sleep_on() follows immediately after
- * interruptible_sleep_on() and that add_timer() follows
- * immediately after interruptible_sleep(). Ugly, isn't it?
- * Maybe adding a wchan field to task_struct would be better,
- * after all...
- */
- {
- unsigned long schedule_frame;
- unsigned long pc;
-
- pc = thread_saved_pc(&p->thread);
- if (pc >= first_sched && pc < last_sched) {
- schedule_frame = ((unsigned long *)p->thread.ksp)[6];
- return ((unsigned long *)schedule_frame)[12];
- }
- return pc;
- }
-#elif defined(__mips__)
- /*
- * The same comment as on the Alpha applies here, too ...
- */
- {
- unsigned long schedule_frame;
- unsigned long pc;
-
- pc = thread_saved_pc(&p->thread);
- if (pc == (unsigned long) interruptible_sleep_on
- || pc == (unsigned long) sleep_on) {
- schedule_frame = ((unsigned long *)p->thread.reg30)[9];
- return ((unsigned long *)schedule_frame)[15];
- }
- if (pc == (unsigned long) interruptible_sleep_on_timeout
- || pc == (unsigned long) sleep_on_timeout) {
- schedule_frame = ((unsigned long *)p->thread.reg30)[9];
- return ((unsigned long *)schedule_frame)[16];
- }
- if (pc >= first_sched && pc < last_sched) {
- printk(KERN_DEBUG "Bug in %s\n", __FUNCTION__);
- }
-
- return pc;
- }
-#elif defined(__mc68000__)
- {
- unsigned long fp, pc;
- unsigned long stack_page;
- int count = 0;
-
- stack_page = (unsigned long)p;
- fp = ((struct switch_stack *)p->thread.ksp)->a6;
- do {
- if (fp < stack_page+sizeof(struct task_struct) ||
- fp >= 8184+stack_page)
- return 0;
- pc = ((unsigned long *)fp)[1];
- /* FIXME: This depends on the order of these functions. */
- if (pc < first_sched || pc >= last_sched)
- return pc;
- fp = *(unsigned long *) fp;
- } while (count++ < 16);
- }
-#elif defined(__powerpc__)
- {
- unsigned long ip, sp;
- unsigned long stack_page = (unsigned long) p;
- int count = 0;
-
- sp = p->thread.ksp;
- do {
- sp = *(unsigned long *)sp;
- if (sp < stack_page || sp >= stack_page + 8188)
- return 0;
- if (count > 0) {
- ip = *(unsigned long *)(sp + 4);
- if (ip < first_sched || ip >= last_sched)
- return ip;
- }
- } while (count++ < 16);
- }
-#elif defined(__arm__)
- {
- unsigned long fp, lr;
- unsigned long stack_page;
- int count = 0;
-
- stack_page = 4096 + (unsigned long)p;
- fp = get_css_fp (&p->tss);
- do {
- if (fp < stack_page || fp > 4092+stack_page)
- return 0;
- lr = pc_pointer (((unsigned long *)fp)[-1]);
- if (lr < first_sched || lr > last_sched)
- return lr;
- fp = *(unsigned long *) (fp - 12);
- } while (count ++ < 16);
- }
-#elif defined (__sparc__)
- {
- unsigned long pc, fp, bias = 0;
- unsigned long task_base = (unsigned long) p;
- struct reg_window *rw;
- int count = 0;
-
-#ifdef __sparc_v9__
- bias = STACK_BIAS;
-#endif
- fp = p->thread.ksp + bias;
- do {
- /* Bogus frame pointer? */
- if (fp < (task_base + sizeof(struct task_struct)) ||
- fp >= (task_base + (2 * PAGE_SIZE)))
- break;
- rw = (struct reg_window *) fp;
- pc = rw->ins[7];
- if (pc < first_sched || pc >= last_sched)
- return pc;
- fp = rw->ins[6] + bias;
- } while (++count < 16);
- }
-#endif
-
- return 0;
-}
-
-#if defined(__i386__)
-# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1019])
-# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
-#elif defined(__alpha__)
- /*
- * See arch/alpha/kernel/ptrace.c for details.
- */
-# define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \
- + (long)&((struct pt_regs *)0)->reg)
-# define KSTK_EIP(tsk) \
- (*(unsigned long *)(PT_REG(pc) + PAGE_SIZE + (unsigned long)(tsk)))
-# define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
-#elif defined(__arm__)
-# define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1022])
-# define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020])
-#elif defined(__mc68000__)
-#define KSTK_EIP(tsk) \
- ({ \
- unsigned long eip = 0; \
- if ((tsk)->thread.esp0 > PAGE_SIZE && \
- MAP_NR((tsk)->thread.esp0) < max_mapnr) \
- eip = ((struct pt_regs *) (tsk)->thread.esp0)->pc; \
- eip; })
-#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
-#elif defined(__powerpc__)
-#define KSTK_EIP(tsk) ((tsk)->thread.regs->nip)
-#define KSTK_ESP(tsk) ((tsk)->thread.regs->gpr[1])
-#elif defined (__sparc_v9__)
-# define KSTK_EIP(tsk) ((tsk)->thread.kregs->tpc)
-# define KSTK_ESP(tsk) ((tsk)->thread.kregs->u_regs[UREG_FP])
-#elif defined(__sparc__)
-# define KSTK_EIP(tsk) ((tsk)->thread.kregs->pc)
-# define KSTK_ESP(tsk) ((tsk)->thread.kregs->u_regs[UREG_FP])
-#elif defined(__mips__)
-# define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg \
- - sizeof(struct pt_regs))
-#define KSTK_TOS(tsk) ((unsigned long)(tsk) + KERNEL_STACK_SIZE - 32)
-# define KSTK_EIP(tsk) (*(unsigned long *)(KSTK_TOS(tsk) + PT_REG(cp0_epc)))
-# define KSTK_ESP(tsk) (*(unsigned long *)(KSTK_TOS(tsk) + PT_REG(regs[29])))
-#elif defined(__sh__)
-# define KSTK_EIP(tsk) ((tsk)->thread.pc)
-# define KSTK_ESP(tsk) ((tsk)->thread.sp)
-#endif
+#include <asm/processor.h>
/* Gcc optimizes away "strlen(x)" for constant x */
#define ADDBUF(buffer, string) \
@@ -913,36 +264,27 @@ extern inline char *task_cap(struct task_struct *p, char *buffer)
}
-static int get_status(int pid, char * buffer)
+/* task is locked, so we are safe here */
+
+int proc_pid_status(struct task_struct *task, char * buffer)
{
char * orig = buffer;
- struct task_struct *tsk;
- struct mm_struct *mm = NULL;
+ struct mm_struct *mm = task->mm;
- read_lock(&tasklist_lock);
- tsk = find_task_by_pid(pid);
- if (tsk)
- mm = tsk->mm;
- if (mm)
- atomic_inc(&mm->mm_users);
- read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
- if (!tsk)
- return 0;
- buffer = task_name(tsk, buffer);
- buffer = task_state(tsk, buffer);
+ buffer = task_name(task, buffer);
+ buffer = task_state(task, buffer);
if (mm)
buffer = task_mem(mm, buffer);
- buffer = task_sig(tsk, buffer);
- buffer = task_cap(tsk, buffer);
- if (mm)
- mmput(mm);
+ buffer = task_sig(task, buffer);
+ buffer = task_cap(task, buffer);
return buffer - orig;
}
-static int get_stat(int pid, char * buffer)
+/* task is locked, so we are safe here */
+
+int proc_pid_stat(struct task_struct *task, char * buffer)
{
- struct task_struct *tsk;
- struct mm_struct *mm = NULL;
+ struct mm_struct *mm = task->mm;
unsigned long vsize, eip, esp, wchan;
long priority, nice;
int tty_pgrp;
@@ -950,16 +292,7 @@ static int get_stat(int pid, char * buffer)
char state;
int res;
- read_lock(&tasklist_lock);
- tsk = find_task_by_pid(pid);
- if (tsk)
- mm = tsk->mm;
- if (mm)
- atomic_inc(&mm->mm_users);
- read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
- if (!tsk)
- return 0;
- state = *get_task_state(tsk);
+ state = *get_task_state(task);
vsize = eip = esp = 0;
if (mm) {
struct vm_area_struct *vma;
@@ -969,55 +302,55 @@ static int get_stat(int pid, char * buffer)
vsize += vma->vm_end - vma->vm_start;
vma = vma->vm_next;
}
- eip = KSTK_EIP(tsk);
- esp = KSTK_ESP(tsk);
+ eip = KSTK_EIP(task);
+ esp = KSTK_ESP(task);
up(&mm->mmap_sem);
}
- wchan = get_wchan(tsk);
+ wchan = get_wchan(task);
- collect_sigign_sigcatch(tsk, &sigign, &sigcatch);
+ collect_sigign_sigcatch(task, &sigign, &sigcatch);
- if (tsk->tty)
- tty_pgrp = tsk->tty->pgrp;
+ if (task->tty)
+ tty_pgrp = task->tty->pgrp;
else
tty_pgrp = -1;
/* scale priority and nice values from timeslices to -20..20 */
/* to make it look like a "normal" Unix priority/nice value */
- priority = tsk->counter;
+ priority = task->counter;
priority = 20 - (priority * 10 + DEF_PRIORITY / 2) / DEF_PRIORITY;
- nice = tsk->priority;
+ nice = task->priority;
nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY;
res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
- pid,
- tsk->comm,
+ task->pid,
+ task->comm,
state,
- tsk->p_pptr->pid,
- tsk->pgrp,
- tsk->session,
- tsk->tty ? kdev_t_to_nr(tsk->tty->device) : 0,
+ task->p_pptr->pid,
+ task->pgrp,
+ task->session,
+ task->tty ? kdev_t_to_nr(task->tty->device) : 0,
tty_pgrp,
- tsk->flags,
- tsk->min_flt,
- tsk->cmin_flt,
- tsk->maj_flt,
- tsk->cmaj_flt,
- HZ_TO_STD(tsk->times.tms_utime),
- HZ_TO_STD(tsk->times.tms_stime),
- HZ_TO_STD(tsk->times.tms_cutime),
- HZ_TO_STD(tsk->times.tms_cstime),
+ task->flags,
+ task->min_flt,
+ task->cmin_flt,
+ task->maj_flt,
+ task->cmaj_flt,
+ task->times.tms_utime,
+ task->times.tms_stime,
+ task->times.tms_cutime,
+ task->times.tms_cstime,
priority,
nice,
0UL /* removed */,
- tsk->it_real_value,
- tsk->start_time,
+ task->it_real_value,
+ task->start_time,
vsize,
mm ? mm->rss : 0, /* you might want to shift this left 3 */
- tsk->rlim ? tsk->rlim[RLIMIT_RSS].rlim_cur : 0,
+ task->rlim ? task->rlim[RLIMIT_RSS].rlim_cur : 0,
mm ? mm->start_code : 0,
mm ? mm->end_code : 0,
mm ? mm->start_stack : 0,
@@ -1027,17 +360,15 @@ static int get_stat(int pid, char * buffer)
* It must be decimal for Linux 2.0 compatibility.
* Use /proc/#/status for real-time signals.
*/
- tsk->signal .sig[0] & 0x7fffffffUL,
- tsk->blocked.sig[0] & 0x7fffffffUL,
+ task->signal .sig[0] & 0x7fffffffUL,
+ task->blocked.sig[0] & 0x7fffffffUL,
sigign .sig[0] & 0x7fffffffUL,
sigcatch .sig[0] & 0x7fffffffUL,
wchan,
- tsk->nswap,
- tsk->cnswap,
- tsk->exit_signal,
- tsk->processor);
- if (mm)
- mmput(mm);
+ task->nswap,
+ task->cnswap,
+ task->exit_signal,
+ task->processor);
return res;
}
@@ -1072,9 +403,9 @@ static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned
++*pages;
if (pte_dirty(page))
++*dirty;
- if (MAP_NR(pte_page(page)) >= max_mapnr)
+ if (pte_pagenr(page) >= max_mapnr)
continue;
- if (page_count(mem_map + MAP_NR(pte_page(page))) > 1)
+ if (page_count(pte_page(page)) > 1)
++*shared;
} while (address < end);
}
@@ -1114,9 +445,9 @@ static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long en
}
}
-static int get_statm(int pid, char * buffer)
+int proc_pid_statm(struct task_struct *task, char * buffer)
{
- struct mm_struct *mm = get_mm(pid);
+ struct mm_struct *mm = task->mm;
int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
if (mm) {
@@ -1143,7 +474,6 @@ static int get_statm(int pid, char * buffer)
vma = vma->vm_next;
}
up(&mm->mmap_sem);
- mmput(mm);
}
return sprintf(buffer,"%d %d %d %d %d %d %d\n",
size, resident, share, trs, lrs, drs, dt);
@@ -1182,10 +512,10 @@ static int get_statm(int pid, char * buffer)
#define MAPS_LINE_MAX MAPS_LINE_MAX8
-static ssize_t read_maps (int pid, struct file * file, char * buf,
+ssize_t proc_pid_read_maps (struct task_struct *task, struct file * file, char * buf,
size_t count, loff_t *ppos)
{
- struct task_struct *p;
+ struct mm_struct *mm = task->mm;
struct vm_area_struct * map, * next;
char * destptr = buf, * buffer;
loff_t lineno;
@@ -1201,25 +531,19 @@ static ssize_t read_maps (int pid, struct file * file, char * buf,
if (!buffer)
goto out;
- retval = -EINVAL;
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
- if (!p)
- goto freepage_out;
-
- if (!p->mm || count == 0)
+ if (!mm || count == 0)
goto getlen_out;
/* Check whether the mmaps could change if we sleep */
- volatile_task = (p != current || atomic_read(&p->mm->mm_users) > 1);
+ volatile_task = (task != current || atomic_read(&mm->mm_users) > 1);
/* decode f_pos */
lineno = *ppos >> MAPS_LINE_SHIFT;
column = *ppos & (MAPS_LINE_LENGTH-1);
/* quickly go to line lineno */
- for (map = p->mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
+ down(&mm->mmap_sem);
+ for (map = mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
continue;
for ( ; map ; map = next ) {
@@ -1260,7 +584,7 @@ static ssize_t read_maps (int pid, struct file * file, char * buf,
len = sprintf(line,
sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8,
- map->vm_start, map->vm_end, str, map->vm_offset,
+ map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
kdevname(dev), ino);
if(map->vm_file) {
@@ -1278,7 +602,9 @@ static ssize_t read_maps (int pid, struct file * file, char * buf,
i = len-column;
if (i > count)
i = count;
+ up(&mm->mmap_sem);
copy_to_user(destptr, line+column, i); /* may have slept */
+ down(&mm->mmap_sem);
destptr += i;
count -= i;
column += i;
@@ -1297,382 +623,34 @@ static ssize_t read_maps (int pid, struct file * file, char * buf,
if (volatile_task)
break;
}
+ up(&mm->mmap_sem);
/* encode f_pos */
*ppos = (lineno << MAPS_LINE_SHIFT) + column;
getlen_out:
retval = destptr - buf;
-
-freepage_out:
free_page((unsigned long)buffer);
out:
return retval;
}
#ifdef __SMP__
-static int get_pidcpu(int pid, char * buffer)
+int proc_pid_cpu(struct task_struct *task, char * buffer)
{
- struct task_struct * tsk = current ;
- int i, len = 0;
-
- read_lock(&tasklist_lock);
- if (pid != tsk->pid)
- tsk = find_task_by_pid(pid);
- read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */
-
- if (tsk == NULL)
- return 0;
+ int i, len;
len = sprintf(buffer,
"cpu %lu %lu\n",
- HZ_TO_STD(tsk->times.tms_utime),
- HZ_TO_STD(tsk->times.tms_stime));
-
+ task->times.tms_utime,
+ task->times.tms_stime);
+
for (i = 0 ; i < smp_num_cpus; i++)
len += sprintf(buffer + len, "cpu%d %lu %lu\n",
i,
- HZ_TO_STD(tsk->per_cpu_utime[cpu_logical_map(i)]),
- HZ_TO_STD(tsk->per_cpu_stime[cpu_logical_map(i)]));
+ task->per_cpu_utime[cpu_logical_map(i)],
+ task->per_cpu_stime[cpu_logical_map(i)]);
return len;
}
#endif
-
-#ifdef CONFIG_MODULES
-extern int get_module_list(char *);
-extern int get_ksyms_list(char *, char **, off_t, int);
-#endif
-extern int get_device_list(char *);
-extern int get_partition_list(char *);
-extern int get_filesystem_list(char *);
-extern int get_filesystem_info( char * );
-extern int get_irq_list(char *);
-extern int get_dma_list(char *);
-extern int get_cpuinfo(char *);
-extern int get_pci_list(char *);
-extern int get_md_status (char *);
-extern int get_rtc_status (char *);
-extern int get_locks_status (char *, char **, off_t, int);
-extern int get_swaparea_info (char *);
-extern int get_hardware_list(char *);
-extern int get_stram_list(char *);
-
-static long get_root_array(char * page, int type, char **start,
- off_t offset, unsigned long length)
-{
- switch (type) {
- case PROC_LOADAVG:
- return get_loadavg(page);
-
- case PROC_UPTIME:
- return get_uptime(page);
-
- case PROC_MEMINFO:
- return get_meminfo(page);
-
-#ifdef CONFIG_PCI
- case PROC_PCI:
- return get_pci_list(page);
-#endif
-
-#ifdef CONFIG_NUBUS
- case PROC_NUBUS:
- return get_nubus_list(page);
-#endif
-
- case PROC_CPUINFO:
- return get_cpuinfo(page);
-
- case PROC_VERSION:
- return get_version(page);
-
-#ifdef CONFIG_DEBUG_MALLOC
- case PROC_MALLOC:
- return get_malloc(page);
-#endif
-
-#ifdef CONFIG_MODULES
- case PROC_MODULES:
- return get_module_list(page);
-
- case PROC_KSYMS:
- return get_ksyms_list(page, start, offset, length);
-#endif
-
- case PROC_STAT:
- return get_kstat(page);
-
- case PROC_SLABINFO:
- return get_slabinfo(page);
-
- case PROC_DEVICES:
- return get_device_list(page);
-
- case PROC_PARTITIONS:
- return get_partition_list(page);
-
- case PROC_INTERRUPTS:
- return get_irq_list(page);
-
- case PROC_FILESYSTEMS:
- return get_filesystem_list(page);
-
- case PROC_DMA:
- return get_dma_list(page);
-
- case PROC_IOPORTS:
- return get_ioport_list(page);
-
- case PROC_MEMORY:
- return get_mem_list(page);
-#ifdef CONFIG_BLK_DEV_MD
- case PROC_MD:
- return get_md_status(page);
-#endif
- case PROC_CMDLINE:
- return get_cmdline(page);
-
- case PROC_MTAB:
- return get_filesystem_info( page );
-
- case PROC_SWAP:
- return get_swaparea_info(page);
-#ifdef CONFIG_RTC
- case PROC_RTC:
- return get_rtc_status(page);
-#endif
-#ifdef CONFIG_SGI_DS1286
- case PROC_RTC:
- return get_ds1286_status(page);
-#endif
- case PROC_LOCKS:
- return get_locks_status(page, start, offset, length);
-#ifdef CONFIG_PROC_HARDWARE
- case PROC_HARDWARE:
- return get_hardware_list(page);
-#endif
-#ifdef CONFIG_STRAM_PROC
- case PROC_STRAM:
- return get_stram_list(page);
-#endif
- }
- return -EBADF;
-}
-
-static int process_unauthorized(int type, int pid)
-{
- struct task_struct *p;
- uid_t euid=0; /* Save the euid keep the lock short */
- int ok = 0;
-
- read_lock(&tasklist_lock);
-
- /*
- * Grab the lock, find the task, save the uid and
- * check it has an mm still (ie its not dead)
- */
-
- p = find_task_by_pid(pid);
- if (p) {
- euid=p->euid;
- ok = p->dumpable;
- if(!cap_issubset(p->cap_permitted, current->cap_permitted))
- ok=0;
- }
-
- read_unlock(&tasklist_lock);
-
- if (!p)
- return 1;
-
- switch(type) {
- case PROC_PID_STATUS:
- case PROC_PID_STATM:
- case PROC_PID_STAT:
- case PROC_PID_MAPS:
- case PROC_PID_CMDLINE:
- case PROC_PID_CPU:
- return 0;
- }
- if(capable(CAP_DAC_OVERRIDE) || (current->fsuid == euid && ok))
- return 0;
- return 1;
-}
-
-
-static int get_process_array(char * page, int pid, int type)
-{
- switch (type) {
- case PROC_PID_STATUS:
- return get_status(pid, page);
- case PROC_PID_ENVIRON:
- return get_env(pid, page);
- case PROC_PID_CMDLINE:
- return get_arg(pid, page);
- case PROC_PID_STAT:
- return get_stat(pid, page);
- case PROC_PID_STATM:
- return get_statm(pid, page);
-#ifdef __SMP__
- case PROC_PID_CPU:
- return get_pidcpu(pid, page);
-#endif
- }
- return -EBADF;
-}
-
-
-static inline int fill_array(char * page, int pid, int type, char **start, off_t offset, int length)
-{
- if (pid)
- return get_process_array(page, pid, type);
- return get_root_array(page, type, start, offset, length);
-}
-
-#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
-
-static ssize_t array_read(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- unsigned long page;
- char *start;
- ssize_t length;
- ssize_t end;
- unsigned int type, pid;
- struct proc_dir_entry *dp;
-
- if (count > PROC_BLOCK_SIZE)
- count = PROC_BLOCK_SIZE;
- if (!(page = __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
- type = inode->i_ino;
- pid = type >> 16;
- type &= 0x0000ffff;
- start = NULL;
- dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
- if (pid && process_unauthorized(type, pid)) {
- free_page(page);
- return -EIO;
- }
-
- if (dp->get_info)
- length = dp->get_info((char *)page, &start, *ppos,
- count, 0);
- else
- length = fill_array((char *) page, pid, type,
- &start, *ppos, count);
- if (length < 0) {
- free_page(page);
- return length;
- }
- if (start != NULL) {
- /* We have had block-adjusting processing! */
- copy_to_user(buf, start, length);
- *ppos += length;
- count = length;
- } else {
- /* Static 4kB (or whatever) block capacity */
- if (*ppos >= length) {
- free_page(page);
- return 0;
- }
- if (count + *ppos > length)
- count = length - *ppos;
- end = count + *ppos;
- copy_to_user(buf, (char *) page + *ppos, count);
- *ppos = end;
- }
- free_page(page);
- return count;
-}
-
-static struct file_operations proc_array_operations = {
- NULL, /* array_lseek */
- array_read,
- NULL, /* array_write */
- NULL, /* array_readdir */
- NULL, /* array_poll */
- NULL, /* array_ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-struct inode_operations proc_array_inode_operations = {
- &proc_array_operations, /* default base directory file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-static ssize_t arraylong_read(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- unsigned int pid = inode->i_ino >> 16;
- unsigned int type = inode->i_ino & 0x0000ffff;
-
- switch (type) {
- case PROC_PID_MAPS:
- return read_maps(pid, file, buf, count, ppos);
- }
- return -EINVAL;
-}
-
-static struct file_operations proc_arraylong_operations = {
- NULL, /* array_lseek */
- arraylong_read,
- NULL, /* array_write */
- NULL, /* array_readdir */
- NULL, /* array_poll */
- NULL, /* array_ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-struct inode_operations proc_arraylong_inode_operations = {
- &proc_arraylong_operations, /* default base directory file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
diff --git a/fs/proc/base.c b/fs/proc/base.c
index f0a0febf8..866bb50d4 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -4,6 +4,13 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*
* proc base directory handling functions
+ *
+ * 1999, Al Viro. Rewritten. Now it covers the whole per-process part.
+ * Instead of using magical inumbers to determine the kind of object
+ * we allocate and fill in-core inodes upon lookup. They don't even
+ * go into icache. We cache the reference to task_struct upon lookup too.
+ * Eventually it should become a filesystem in its own. We don't use the
+ * rest of procfs anymore.
*/
#include <asm/uaccess.h>
@@ -14,28 +21,336 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/init.h>
-
-static struct file_operations proc_base_operations = {
- NULL, /* lseek - default */
- NULL, /* read - bad */
- NULL, /* write - bad */
- proc_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 */
-};
+#include <linux/file.h>
/*
- * proc directories can do almost nothing..
+ * For hysterical raisins we keep the same inumbers as in the old procfs.
+ * Feel free to change the macro below - just keep the range distinct from
+ * inumbers of the rest of procfs (currently those are in 0x0000--0xffff).
+ * As soon as we'll get a separate superblock we will be able to forget
+ * about magical ranges too.
*/
-static struct inode_operations proc_base_inode_operations = {
- &proc_base_operations, /* default base directory file-ops */
+
+#define fake_ino(pid,ino) (((pid)<<16)|(ino))
+
+ssize_t proc_pid_read_maps(struct task_struct*,struct file*,char*,size_t,loff_t*);
+int proc_pid_stat(struct task_struct*,char*);
+int proc_pid_status(struct task_struct*,char*);
+int proc_pid_statm(struct task_struct*,char*);
+int proc_pid_cpu(struct task_struct*,char*);
+
+static struct dentry *proc_fd_link(struct inode *inode)
+{
+ if (inode->u.proc_i.file)
+ return dget(inode->u.proc_i.file->f_dentry);
+ return NULL;
+}
+
+static struct dentry *proc_exe_link(struct inode *inode)
+{
+ struct mm_struct * mm;
+ struct vm_area_struct * vma;
+ struct dentry *result = NULL;
+ struct task_struct *task = inode->u.proc_i.task;
+
+ if (!task_lock(task))
+ return NULL;
+ mm = task->mm;
+ if (!mm)
+ goto out;
+ down(&mm->mmap_sem);
+ vma = mm->mmap;
+ while (vma) {
+ if ((vma->vm_flags & VM_EXECUTABLE) &&
+ vma->vm_file) {
+ result = dget(vma->vm_file->f_dentry);
+ break;
+ }
+ vma = vma->vm_next;
+ }
+ up(&mm->mmap_sem);
+out:
+ task_unlock(task);
+ return result;
+}
+
+static struct dentry *proc_cwd_link(struct inode *inode)
+{
+ struct dentry *result = NULL;
+ if (task_lock(inode->u.proc_i.task)) {
+ struct fs_struct *fs = inode->u.proc_i.task->fs;
+ if (fs)
+ result = dget(fs->pwd);
+ task_unlock(inode->u.proc_i.task);
+ }
+ return result;
+}
+
+static struct dentry *proc_root_link(struct inode *inode)
+{
+ struct dentry *result = NULL;
+ if (task_lock(inode->u.proc_i.task)) {
+ struct fs_struct *fs = inode->u.proc_i.task->fs;
+ if (fs)
+ result = dget(fs->root);
+ task_unlock(inode->u.proc_i.task);
+ }
+ return result;
+}
+
+/* task is locked and can't drop mm, so we are safe */
+
+static int proc_pid_environ(struct task_struct *task, char * buffer)
+{
+ struct mm_struct *mm = task->mm;
+ int res = 0;
+ if (mm)
+ res = access_process_vm(task, mm->env_start, buffer,
+ mm->env_end - mm->env_start, 0);
+ return res;
+}
+
+/* task is locked and can't drop mm, so we are safe */
+
+static int proc_pid_cmdline(struct task_struct *task, char * buffer)
+{
+ struct mm_struct *mm = task->mm;
+ int res = 0;
+ if (mm)
+ res = access_process_vm(task, mm->arg_start, buffer,
+ mm->arg_end - mm->arg_start, 0);
+ return res;
+}
+
+/************************************************************************/
+/* Here the fs part begins */
+/************************************************************************/
+
+/* permission checks */
+
+static int standard_permission(struct inode *inode, int mask)
+{
+ int mode = inode->i_mode;
+
+ if ((mask & S_IWOTH) && IS_RDONLY(inode) &&
+ (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
+ return -EROFS; /* Nobody gets write access to a read-only fs */
+ else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
+ return -EACCES; /* Nobody gets write access to an immutable file */
+ else if (current->fsuid == inode->i_uid)
+ mode >>= 6;
+ else if (in_group_p(inode->i_gid))
+ mode >>= 3;
+ if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE))
+ return 0;
+ /* read and search access */
+ if ((mask == S_IROTH) ||
+ (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH))))
+ if (capable(CAP_DAC_READ_SEARCH))
+ return 0;
+ return -EACCES;
+}
+
+static int proc_permission(struct inode *inode, int mask)
+{
+ struct dentry *de, *base, *root;
+ struct super_block *our_sb, *sb, *below;
+
+ if (standard_permission(inode, mask) != 0)
+ return -EACCES;
+
+ base = current->fs->root;
+ de = root = proc_root_link(inode); /* Ewww... */
+
+ if (!de)
+ return -ENOENT;
+
+ our_sb = base->d_inode->i_sb;
+ sb = de->d_inode->i_sb;
+ while (sb != our_sb) {
+ de = sb->s_root->d_covers;
+ below = de->d_inode->i_sb;
+ if (sb == below)
+ goto out;
+ sb = below;
+ }
+
+ if (!is_subdir(de, base))
+ goto out;
+
+ dput(root);
+ return 0;
+out:
+ dput(root);
+ return -EACCES;
+}
+
+static ssize_t pid_maps_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
+{
+ struct inode * inode = file->f_dentry->d_inode;
+ struct task_struct *task = inode->u.proc_i.task;
+ ssize_t res;
+
+ if (!task_lock(task))
+ return -EIO;
+ res = proc_pid_read_maps(task, file, buf, count, ppos);
+ task_unlock(task);
+ return res;
+}
+
+static struct file_operations proc_maps_operations = {
+ NULL, /* array_lseek */
+ pid_maps_read,
+};
+
+struct inode_operations proc_maps_inode_operations = {
+ &proc_maps_operations, /* default base directory file-ops */
+};
+
+#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
+
+static ssize_t proc_info_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
+{
+ struct inode * inode = file->f_dentry->d_inode;
+ unsigned long page;
+ ssize_t length;
+ ssize_t end;
+ struct task_struct *task = inode->u.proc_i.task;
+
+ if (count > PROC_BLOCK_SIZE)
+ count = PROC_BLOCK_SIZE;
+ if (!(page = __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+
+ if (!task_lock(task)) {
+ free_page(page);
+ return -EIO;
+ }
+
+ length = inode->u.proc_i.op.proc_read(task, (char*)page);
+
+ task_unlock(task);
+
+ if (length < 0) {
+ free_page(page);
+ return length;
+ }
+ /* Static 4kB (or whatever) block capacity */
+ if (*ppos >= length) {
+ free_page(page);
+ return 0;
+ }
+ if (count + *ppos > length)
+ count = length - *ppos;
+ end = count + *ppos;
+ copy_to_user(buf, (char *) page + *ppos, count);
+ *ppos = end;
+ free_page(page);
+ return count;
+}
+
+static struct file_operations proc_info_file_operations = {
+ NULL, /* lseek */
+ proc_info_read, /* read */
+};
+
+static struct inode_operations proc_info_inode_operations = {
+ &proc_info_file_operations, /* default proc file-ops */
+};
+
+#define MAY_PTRACE(p) \
+(p==current||(p->p_pptr==current&&(p->flags&PF_PTRACED)&&p->state==TASK_STOPPED))
+
+static ssize_t mem_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_struct *task = file->f_dentry->d_inode->u.proc_i.task;
+ char *page;
+ unsigned long src = *ppos;
+ int copied = 0;
+
+ if (!MAY_PTRACE(task))
+ return -ESRCH;
+
+ page = (char *)__get_free_page(GFP_USER);
+ if (!page)
+ return -ENOMEM;
+
+ while (count > 0) {
+ int this_len, retval;
+
+ this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+ retval = access_process_vm(task, src, page, this_len, 0);
+ if (!retval) {
+ if (!copied)
+ copied = -EIO;
+ break;
+ }
+ if (copy_to_user(buf, page, retval)) {
+ copied = -EFAULT;
+ break;
+ }
+ copied += retval;
+ src += retval;
+ buf += retval;
+ count -= retval;
+ }
+ *ppos = src;
+ free_page((unsigned long) page);
+ return copied;
+}
+
+static ssize_t mem_write(struct file * file, const char * buf,
+ size_t count, loff_t *ppos)
+{
+ int copied = 0;
+ char *page;
+ struct task_struct *task = file->f_dentry->d_inode->u.proc_i.task;
+ unsigned long dst = *ppos;
+
+ if (!MAY_PTRACE(task))
+ return -ESRCH;
+
+ page = (char *)__get_free_page(GFP_USER);
+ if (!page)
+ return -ENOMEM;
+
+ while (count > 0) {
+ int this_len, retval;
+
+ this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+ if (copy_from_user(page, buf, this_len)) {
+ copied = -EFAULT;
+ break;
+ }
+ retval = access_process_vm(task, dst, page, this_len, 1);
+ if (!retval) {
+ if (!copied)
+ copied = -EIO;
+ break;
+ }
+ copied += retval;
+ buf += retval;
+ dst += retval;
+ count -= retval;
+ }
+ *ppos = dst;
+ free_page((unsigned long) page);
+ return copied;
+}
+
+static struct file_operations proc_mem_operations = {
+ NULL, /* lseek - default */
+ mem_read,
+ mem_write,
+};
+
+static struct inode_operations proc_mem_inode_operations = {
+ &proc_mem_operations, /* default base directory file-ops */
NULL, /* create */
- proc_lookup, /* lookup */
+ NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
@@ -50,161 +365,653 @@ static struct inode_operations proc_base_inode_operations = {
NULL, /* writepage */
NULL, /* flushpage */
NULL, /* truncate */
- NULL, /* permission */
+ proc_permission, /* permission */
NULL, /* smap */
NULL /* revalidate */
};
-/*
- * The fill argument is non-zero when the inode is being filled ...
- * we don't need to do anything when it's being deleted.
- */
-static void proc_pid_fill_inode(struct inode * inode, int fill)
+static struct dentry * proc_pid_follow_link(struct dentry *dentry,
+ struct dentry *base,
+ unsigned int follow)
{
- struct task_struct *p;
- int pid = inode->i_ino >> 16;
- int ino = inode->i_ino & 0xffff;
+ struct inode *inode = dentry->d_inode;
+ struct dentry * result;
+ int error;
- read_lock(&tasklist_lock);
- if (fill && (p = find_task_by_pid(pid)) != NULL) {
- uid_t uid = 0;
- gid_t gid = 0;
- if (p->dumpable || ino == PROC_PID_INO) {
- uid = p->euid;
- gid = p->egid;
- }
- inode->i_uid = uid;
- inode->i_gid = gid;
+ /* We don't need a base pointer in the /proc filesystem */
+ dput(base);
+
+ error = proc_permission(inode, MAY_EXEC);
+ result = ERR_PTR(error);
+ if (error)
+ goto out;
+
+ result = inode->u.proc_i.op.proc_get_link(inode);
+out:
+ if (!result)
+ result = ERR_PTR(-ENOENT);
+ return result;
+}
+
+static int do_proc_readlink(struct dentry *dentry, char * buffer, int buflen)
+{
+ struct inode * inode;
+ char * tmp = (char*)__get_free_page(GFP_KERNEL), *path, *pattern;
+ int len;
+
+ if (!tmp)
+ return -ENOMEM;
+
+ /* Check for special dentries.. */
+ pattern = NULL;
+ inode = dentry->d_inode;
+ if (inode && IS_ROOT(dentry)) {
+ if (S_ISSOCK(inode->i_mode))
+ pattern = "socket:[%lu]";
+ if (S_ISFIFO(inode->i_mode))
+ pattern = "pipe:[%lu]";
}
- read_unlock(&tasklist_lock);
+
+ if (pattern) {
+ len = sprintf(tmp, pattern, inode->i_ino);
+ path = tmp;
+ } else {
+ path = d_path(dentry, tmp, PAGE_SIZE);
+ len = tmp + PAGE_SIZE - 1 - path;
+ }
+
+ if (len < buflen)
+ buflen = len;
+ copy_to_user(buffer, path, buflen);
+ free_page((unsigned long)tmp);
+ return buflen;
}
-/*
- * This is really a pseudo-entry, and only links
- * backwards to the parent with no link from the
- * root directory to this. This way we can have just
- * one entry for every /proc/<pid>/ directory.
- */
-struct proc_dir_entry proc_pid = {
- PROC_PID_INO, 5, "<pid>",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_base_inode_operations,
- NULL, proc_pid_fill_inode,
- NULL, &proc_root, NULL
-};
-
-static struct proc_dir_entry proc_pid_status = {
- PROC_PID_STATUS, 6, "status",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_mem = {
- PROC_PID_MEM, 3, "mem",
- S_IFREG | S_IRUSR | S_IWUSR, 1, 0, 0,
- 0, &proc_mem_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_cwd = {
- PROC_PID_CWD, 3, "cwd",
- S_IFLNK | S_IRWXU, 1, 0, 0,
- 0, &proc_link_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_root = {
- PROC_PID_ROOT, 4, "root",
- S_IFLNK | S_IRWXU, 1, 0, 0,
- 0, &proc_link_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_exe = {
- PROC_PID_EXE, 3, "exe",
- S_IFLNK | S_IRWXU, 1, 0, 0,
- 0, &proc_link_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_fd = {
- PROC_PID_FD, 2, "fd",
- S_IFDIR | S_IRUSR | S_IXUSR, 2, 0, 0,
- 0, &proc_fd_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_environ = {
- PROC_PID_ENVIRON, 7, "environ",
- S_IFREG | S_IRUSR, 1, 0, 0,
- 0, &proc_array_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_cmdline = {
- PROC_PID_CMDLINE, 7, "cmdline",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_stat = {
- PROC_PID_STAT, 4, "stat",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_statm = {
- PROC_PID_STATM, 5, "statm",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- NULL, proc_pid_fill_inode,
-};
-static struct proc_dir_entry proc_pid_maps = {
- PROC_PID_MAPS, 4, "maps",
- S_IFIFO | S_IRUGO, 1, 0, 0,
- 0, &proc_arraylong_inode_operations,
- NULL, proc_pid_fill_inode,
+static int proc_pid_readlink(struct dentry * dentry, char * buffer, int buflen)
+{
+ int error;
+ struct inode *inode = dentry->d_inode;
+
+ error = proc_permission(inode, MAY_EXEC);
+ if (error)
+ goto out;
+
+ dentry = inode->u.proc_i.op.proc_get_link(inode);
+ error = -ENOENT;
+ if (!dentry)
+ goto out;
+
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto out;
+
+ error = do_proc_readlink(dentry, buffer, buflen);
+ dput(dentry);
+out:
+ return error;
+}
+
+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 */
};
+/* reading from directory - bad */
+
+static ssize_t proc_dir_read (struct file * filp, char * buf,
+ size_t count, loff_t *ppos)
+{
+ return -EISDIR;
+}
+
+struct pid_entry {
+ int type;
+ int len;
+ char *name;
+ mode_t mode;
+};
+
+enum pid_directory_inos {
+ PROC_PID_INO = 2,
+ PROC_PID_STATUS,
+ PROC_PID_MEM,
+ PROC_PID_CWD,
+ PROC_PID_ROOT,
+ PROC_PID_EXE,
+ PROC_PID_FD,
+ PROC_PID_ENVIRON,
+ PROC_PID_CMDLINE,
+ PROC_PID_STAT,
+ PROC_PID_STATM,
+ PROC_PID_MAPS,
#if CONFIG_AP1000
-static struct proc_dir_entry proc_pid_ringbuf = {
- PROC_PID_RINGBUF, 7, "ringbuf",
- S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
- 0, &proc_ringbuf_inode_operations,
- NULL, proc_pid_fill_inode,
+ PROC_PID_RINGBUF,
+#endif
+ PROC_PID_CPU,
+ PROC_PID_FD_DIR = 0x8000, /* 0x8000-0xffff */
};
+
+#define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
+static struct pid_entry base_stuff[] = {
+ E(PROC_PID_FD, "fd", S_IFDIR|S_IRUSR|S_IXUSR),
+ E(PROC_PID_ENVIRON, "environ", S_IFREG|S_IRUSR),
+ E(PROC_PID_STATUS, "status", S_IFREG|S_IRUGO),
+ E(PROC_PID_CMDLINE, "cmdline", S_IFREG|S_IRUGO),
+ E(PROC_PID_STAT, "stat", S_IFREG|S_IRUGO),
+ E(PROC_PID_STATM, "statm", S_IFREG|S_IRUGO),
+#ifdef SMP
+ E(PROC_PID_CPU, "cpu", S_IFREG|S_IRUGO),
+#endif
+#if CONFIG_AP1000
+ E(PROC_PID_RINGBUF, "ringbuf", S_IFREG|S_IRUGO|S_IWUSR),
#endif
+ E(PROC_PID_MAPS, "maps", S_IFREG|S_IRUGO),
+ E(PROC_PID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR),
+ E(PROC_PID_CWD, "cwd", S_IFLNK|S_IRWXUGO),
+ E(PROC_PID_ROOT, "root", S_IFLNK|S_IRWXUGO),
+ E(PROC_PID_EXE, "exe", S_IFLNK|S_IRWXUGO),
+ {0,0,NULL,0}
+};
+#undef E
+
+#define NUMBUF 10
+
+static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct task_struct *p = inode->u.proc_i.task;
+ unsigned int fd, pid, ino;
+ int retval;
+ char buf[NUMBUF];
+
+ retval = 0;
+ pid = p->pid;
+
+ fd = filp->f_pos;
+ switch (fd) {
+ case 0:
+ if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0)
+ goto out;
+ filp->f_pos++;
+ case 1:
+ ino = fake_ino(pid, PROC_PID_INO);
+ if (filldir(dirent, "..", 2, 1, ino) < 0)
+ goto out;
+ filp->f_pos++;
+ default:
+ for (fd = filp->f_pos-2;
+ p->p_pptr && p->files && fd < p->files->max_fds;
+ fd++, filp->f_pos++) {
+ unsigned int i,j;
+
+ if (!fcheck_task(p, fd))
+ continue;
+
+ j = NUMBUF;
+ i = fd;
+ do {
+ j--;
+ buf[j] = '0' + (i % 10);
+ i /= 10;
+ } while (i);
+
+ ino = fake_ino(pid, PROC_PID_FD_DIR + fd);
+ if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino) < 0)
+ break;
+
+ }
+ }
+out:
+ return retval;
+}
+
+static int proc_base_readdir(struct file * filp,
+ void * dirent, filldir_t filldir)
+{
+ int i;
+ int pid;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct pid_entry *p;
+
+ pid = inode->u.proc_i.task->pid;
+ if (!inode->u.proc_i.task->p_pptr)
+ return -ENOENT;
+ i = filp->f_pos;
+ switch (i) {
+ case 0:
+ if (filldir(dirent, ".", 1, i, inode->i_ino) < 0)
+ return 0;
+ i++;
+ filp->f_pos++;
+ /* fall through */
+ case 1:
+ if (filldir(dirent, "..", 2, i, PROC_ROOT_INO) < 0)
+ return 0;
+ i++;
+ filp->f_pos++;
+ /* fall through */
+ default:
+ i -= 2;
+ if (i>=sizeof(base_stuff)/sizeof(base_stuff[0]))
+ return 1;
+ p = base_stuff + i;
+ while (p->name) {
+ if (filldir(dirent, p->name, p->len, filp->f_pos, fake_ino(pid, p->type)) < 0)
+ return 0;
+ filp->f_pos++;
+ p++;
+ }
+ }
+ return 1;
+}
+
+/* building an inode */
+
+static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino)
+{
+ struct inode * inode;
+
+ /* We need a new inode */
+
+ inode = get_empty_inode();
+ if (!inode)
+ goto out;
+
+ /* Common stuff */
+
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_ino = fake_ino(task->pid, ino);
+
+ inode->u.proc_i.file = NULL;
+ /*
+ * grab the reference to task.
+ */
+ inode->u.proc_i.task = task;
+ atomic_inc(&mem_map[MAP_NR(task)].count);
+ if (!task->p_pptr)
+ goto out_unlock;
-#ifdef __SMP__
-static struct proc_dir_entry proc_pid_cpu = {
- PROC_PID_CPU, 3, "cpu",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations,
- NULL, proc_pid_fill_inode,
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ if (ino == PROC_PID_INO || task->dumpable) {
+ inode->i_uid = task->euid;
+ inode->i_gid = task->egid;
+ }
+
+out:
+ return inode;
+
+out_unlock:
+ iput(inode);
+ return NULL;
+}
+
+/* dentry stuff */
+
+static int pid_fd_revalidate(struct dentry * dentry, int flags)
+{
+ return 0;
+}
+
+static int pid_base_revalidate(struct dentry * dentry, int flags)
+{
+ if (dentry->d_inode->u.proc_i.task->p_pptr)
+ return 1;
+ d_drop(dentry);
+ return 0;
+}
+
+static void pid_delete_dentry(struct dentry * dentry)
+{
+ d_drop(dentry);
+}
+
+static struct dentry_operations pid_fd_dentry_operations =
+{
+ pid_fd_revalidate, /* revalidate */
+ NULL, /* d_hash */
+ NULL, /* d_compare */
+ pid_delete_dentry /* d_delete(struct dentry *) */
+};
+
+static struct dentry_operations pid_dentry_operations =
+{
+ NULL, /* revalidate */
+ NULL, /* d_hash */
+ NULL, /* d_compare */
+ pid_delete_dentry /* d_delete(struct dentry *) */
+};
+
+static struct dentry_operations pid_base_dentry_operations =
+{
+ pid_base_revalidate, /* revalidate */
+ NULL, /* d_hash */
+ NULL, /* d_compare */
+ pid_delete_dentry /* d_delete(struct dentry *) */
+};
+
+/* Lookups */
+
+static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry)
+{
+ unsigned int fd, c;
+ struct task_struct *task = dir->u.proc_i.task;
+ struct file * file;
+ struct files_struct * files;
+ struct inode *inode;
+ const char *name;
+ int len;
+
+ fd = 0;
+ len = dentry->d_name.len;
+ name = dentry->d_name.name;
+ if (len > 1 && *name == '0') goto out;
+ while (len-- > 0) {
+ c = *name - '0';
+ name++;
+ if (c > 9)
+ goto out;
+ fd *= 10;
+ fd += c;
+ if (fd & 0xffff8000)
+ goto out;
+ }
+
+ inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_FD_DIR+fd);
+ if (!inode)
+ goto out;
+ /* FIXME */
+ files = task->files;
+ if (!files) /* can we ever get here if that's the case? */
+ goto out_unlock;
+ read_lock(&files->file_lock);
+ file = inode->u.proc_i.file = fcheck_task(task, fd);
+ if (!file)
+ goto out_unlock2;
+ get_file(file);
+ read_unlock(&files->file_lock);
+ inode->i_op = &proc_pid_link_inode_operations;
+ inode->i_size = 64;
+ inode->i_mode = S_IFLNK;
+ inode->u.proc_i.op.proc_get_link = proc_fd_link;
+ if (file->f_mode & 1)
+ inode->i_mode |= S_IRUSR | S_IXUSR;
+ if (file->f_mode & 2)
+ inode->i_mode |= S_IWUSR | S_IXUSR;
+ dentry->d_op = &pid_fd_dentry_operations;
+ d_add(dentry, inode);
+ return NULL;
+
+out_unlock2:
+ read_unlock(&files->file_lock);
+out_unlock:
+ iput(inode);
+out:
+ return ERR_PTR(-ENOENT);
+}
+
+static struct file_operations proc_fd_operations = {
+ NULL, /* lseek - default */
+ proc_dir_read, /* read - bad */
+ NULL, /* write - bad */
+ proc_readfd, /* readdir */
};
-#endif
-void __init proc_base_init(void)
+/*
+ * proc directories can do almost nothing..
+ */
+static struct inode_operations proc_fd_inode_operations = {
+ &proc_fd_operations, /* default base directory file-ops */
+ NULL, /* create */
+ proc_lookupfd, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* get_block */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* flushpage */
+ NULL, /* truncate */
+ proc_permission, /* permission */
+};
+
+static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
{
+ struct inode *inode;
+ int error;
+ struct task_struct *task = dir->u.proc_i.task;
+ struct pid_entry *p;
+
+ error = -ENOENT;
+ inode = NULL;
+
+ for (p = base_stuff; p->name; p++) {
+ if (p->len != dentry->d_name.len)
+ continue;
+ if (!memcmp(dentry->d_name.name, p->name, p->len))
+ break;
+ }
+ if (!p->name)
+ goto out;
+
+ error = -EINVAL;
+ inode = proc_pid_make_inode(dir->i_sb, task, p->type);
+ if (!inode)
+ goto out;
+
+ inode->i_mode = p->mode;
+ /*
+ * Yes, it does not scale. And it should not. Don't add
+ * new entries into /proc/<pid>/ without very good reasons.
+ */
+ switch(p->type) {
+ case PROC_PID_FD:
+ inode->i_nlink = 2;
+ inode->i_op = &proc_fd_inode_operations;
+ break;
+ case PROC_PID_EXE:
+ inode->i_op = &proc_pid_link_inode_operations;
+ inode->u.proc_i.op.proc_get_link = proc_exe_link;
+ break;
+ case PROC_PID_CWD:
+ inode->i_op = &proc_pid_link_inode_operations;
+ inode->u.proc_i.op.proc_get_link = proc_cwd_link;
+ break;
+ case PROC_PID_ROOT:
+ inode->i_op = &proc_pid_link_inode_operations;
+ inode->u.proc_i.op.proc_get_link = proc_root_link;
+ break;
+ case PROC_PID_ENVIRON:
+ inode->i_op = &proc_info_inode_operations;
+ inode->u.proc_i.op.proc_read = proc_pid_environ;
+ break;
+ case PROC_PID_STATUS:
+ inode->i_op = &proc_info_inode_operations;
+ inode->u.proc_i.op.proc_read = proc_pid_status;
+ break;
+ case PROC_PID_STAT:
+ inode->i_op = &proc_info_inode_operations;
+ inode->u.proc_i.op.proc_read = proc_pid_stat;
+ break;
+ case PROC_PID_CMDLINE:
+ inode->i_op = &proc_info_inode_operations;
+ inode->u.proc_i.op.proc_read = proc_pid_cmdline;
+ break;
+ case PROC_PID_STATM:
+ inode->i_op = &proc_info_inode_operations;
+ inode->u.proc_i.op.proc_read = proc_pid_statm;
+ break;
+ case PROC_PID_MAPS:
+ inode->i_op = &proc_maps_inode_operations;
+ break;
+#ifdef SMP
+ case PROC_PID_CPU:
+ inode->i_op = &proc_info_inode_operations;
+ inode->u.proc_i.op.proc_read = proc_pid_cpu;
+ break;
+#endif
#if CONFIG_AP1000
- proc_register(&proc_pid, &proc_pid_ringbuf);
+ case PROC_PID_RINGBUF:
+ inode->i_op = &proc_ringbuf_inode_operations;
+ break;
#endif
- proc_register(&proc_pid, &proc_pid_status);
- proc_register(&proc_pid, &proc_pid_mem);
- proc_register(&proc_pid, &proc_pid_cwd);
- proc_register(&proc_pid, &proc_pid_root);
- proc_register(&proc_pid, &proc_pid_exe);
- proc_register(&proc_pid, &proc_pid_fd);
- proc_register(&proc_pid, &proc_pid_environ);
- proc_register(&proc_pid, &proc_pid_cmdline);
- proc_register(&proc_pid, &proc_pid_stat);
- proc_register(&proc_pid, &proc_pid_statm);
- proc_register(&proc_pid, &proc_pid_maps);
-#ifdef __SMP__
- proc_register(&proc_pid, &proc_pid_cpu);
-#endif
+ case PROC_PID_MEM:
+ inode->i_op = &proc_mem_inode_operations;
+ break;
+ default:
+ printk("procfs: impossible type (%d)",p->type);
+ iput(inode);
+ return ERR_PTR(-EINVAL);
+ }
+ dentry->d_op = &pid_dentry_operations;
+ d_add(dentry, inode);
+ return NULL;
+
+out:
+ return ERR_PTR(error);
+}
+
+static struct file_operations proc_base_operations = {
+ NULL, /* lseek - default */
+ proc_dir_read, /* read - bad */
+ NULL, /* write - bad */
+ proc_base_readdir, /* readdir */
+};
+
+static struct inode_operations proc_base_inode_operations = {
+ &proc_base_operations, /* default base directory file-ops */
+ NULL, /* create */
+ proc_base_lookup, /* lookup */
};
+struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry)
+{
+ unsigned int pid, c;
+ struct task_struct *task;
+ const char *name;
+ struct inode *inode;
+ int len;
+
+ pid = 0;
+ name = dentry->d_name.name;
+ len = dentry->d_name.len;
+ while (len-- > 0) {
+ c = *name - '0';
+ name++;
+ if (c > 9)
+ goto out;
+ pid *= 10;
+ pid += c;
+ if (!pid)
+ goto out;
+ if (pid & 0xffff0000)
+ goto out;
+ }
+
+ read_lock(&tasklist_lock);
+ task = find_task_by_pid(pid);
+ if (task)
+ atomic_inc(&mem_map[MAP_NR(task)].count);
+ read_unlock(&tasklist_lock);
+ if (!task)
+ goto out;
+
+ inode = proc_pid_make_inode(dir->i_sb, task, PROC_PID_INO);
+
+ free_task_struct(task);
+ if (!inode)
+ goto out;
+ inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
+ inode->i_op = &proc_base_inode_operations;
+ inode->i_nlink = 3;
+ inode->i_flags|=S_IMMUTABLE;
+ dentry->d_op = &pid_base_dentry_operations;
+ d_add(dentry, inode);
+ return NULL;
+out:
+ return ERR_PTR(-ENOENT);
+}
+
+void proc_pid_delete_inode(struct inode *inode)
+{
+ if (inode->u.proc_i.file)
+ fput(inode->u.proc_i.file);
+ free_task_struct(inode->u.proc_i.task);
+}
+#define PROC_NUMBUF 10
+#define PROC_MAXPIDS 20
+
+/*
+ * Get a few pid's to return for filldir - we need to hold the
+ * tasklist lock while doing this, and we must release it before
+ * we actually do the filldir itself, so we use a temp buffer..
+ */
+static int get_pid_list(int index, unsigned int *pids)
+{
+ struct task_struct *p;
+ int nr_pids = 0;
+ index -= FIRST_PROCESS_ENTRY;
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ int pid = p->pid;
+ if (!pid)
+ continue;
+ if (--index >= 0)
+ continue;
+ pids[nr_pids] = pid;
+ nr_pids++;
+ if (nr_pids >= PROC_MAXPIDS)
+ break;
+ }
+ read_unlock(&tasklist_lock);
+ return nr_pids;
+}
+int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
+{
+ unsigned int pid_array[PROC_MAXPIDS];
+ char buf[PROC_NUMBUF];
+ unsigned int nr = filp->f_pos;
+ unsigned int nr_pids, i;
+ nr_pids = get_pid_list(nr, pid_array);
+ for (i = 0; i < nr_pids; i++) {
+ int pid = pid_array[i];
+ ino_t ino = fake_ino(pid,PROC_PID_INO);
+ unsigned long j = PROC_NUMBUF;
+ do {
+ j--;
+ buf[j] = '0' + (pid % 10);
+ pid /= 10;
+ } while (pid);
+ if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino) < 0)
+ break;
+ filp->f_pos++;
+ }
+ return 0;
+}
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
deleted file mode 100644
index 1862f6f5f..000000000
--- a/fs/proc/fd.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * linux/fs/proc/fd.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * proc fd directory handling functions
- *
- * 01-May-98 Edgar Toernig <froese@gmx.de>
- * Added support for more than 256 fds.
- * Limit raised to 32768.
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/file.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-
-#include <asm/uaccess.h>
-
-static int proc_readfd(struct file *, void *, filldir_t);
-static struct dentry *proc_lookupfd(struct inode *, struct dentry *);
-
-static struct file_operations proc_fd_operations = {
- NULL, /* lseek - default */
- NULL, /* read - bad */
- NULL, /* write - bad */
- proc_readfd, /* 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 */
-};
-
-/*
- * proc directories can do almost nothing..
- */
-struct inode_operations proc_fd_inode_operations = {
- &proc_fd_operations, /* default base directory file-ops */
- NULL, /* create */
- proc_lookupfd, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- proc_permission, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-/*
- * NOTE! Normally we'd indicate that a file does not
- * exist by creating a negative dentry and returning
- * a successful return code. However, for this case
- * we do not want to create negative dentries, because
- * the state of the world can change behind our backs.
- *
- * Thus just return -ENOENT instead.
- */
-static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry)
-{
- unsigned int ino, pid, fd, c;
- struct task_struct * p;
- struct file * file;
- struct inode *inode;
- const char *name;
- int len, err;
-
- err = -ENOENT;
- ino = dir->i_ino;
- pid = ino >> 16;
- ino &= 0x0000ffff;
-
- if (!pid || ino != PROC_PID_FD)
- goto out;
-
- fd = 0;
- len = dentry->d_name.len;
- name = dentry->d_name.name;
- if (len > 1 && *name == '0') goto out;
- while (len-- > 0) {
- c = *name - '0';
- name++;
- if (c > 9)
- goto out;
- fd *= 10;
- fd += c;
- if (fd & 0xffff8000)
- goto out;
- }
-
- read_lock(&tasklist_lock);
- file = NULL;
- p = find_task_by_pid(pid);
- if (p && p->files)
- file = fcheck_task(p, fd);
- read_unlock(&tasklist_lock);
-
- /*
- * File handle is invalid if it is out of range, if the process
- * has no files (Zombie) if the file is closed, or if its inode
- * is NULL
- */
-
- if (!file)
- goto out;
-
- ino = (pid << 16) + PROC_PID_FD_DIR + fd;
- inode = proc_get_inode(dir->i_sb, ino, NULL);
- if (inode) {
- dentry->d_op = &proc_dentry_operations;
- d_add(dentry, inode);
- return NULL;
- }
-out:
- return ERR_PTR(err);
-}
-
-#define NUMBUF 10
-
-static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
-{
- struct inode *inode = filp->f_dentry->d_inode;
- struct task_struct *p, *tmp;
- unsigned int fd, pid, ino;
- int retval;
- char buf[NUMBUF];
-
- retval = 0;
- ino = inode->i_ino;
- pid = ino >> 16;
- ino &= 0x0000ffff;
- if (ino != PROC_PID_FD)
- goto out;
-
- for (fd = filp->f_pos; fd < 2; fd++, filp->f_pos++) {
- ino = inode->i_ino;
- if (fd)
- ino = (ino & 0xffff0000) | PROC_PID_INO;
- if (filldir(dirent, "..", fd+1, fd, ino) < 0)
- goto out;
- }
-
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (!p)
- goto out_unlock;
-
- for (fd -= 2 ; p->files && fd < p->files->max_fds; fd++, filp->f_pos++)
- {
- unsigned int i,j;
-
- if (!fcheck_task(p, fd))
- continue;
-
- j = NUMBUF;
- i = fd;
- do {
- j--;
- buf[j] = '0' + (i % 10);
- i /= 10;
- } while (i);
-
- /* Drop the task lock, as the filldir function may block */
- read_unlock(&tasklist_lock);
-
- ino = (pid << 16) + PROC_PID_FD_DIR + fd;
- if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino) < 0)
- goto out;
-
- read_lock(&tasklist_lock);
- /*
- * filldir() might have slept, so we must
- * re-validate "p". This is fast enough due
- * to the pidhash
- */
- tmp = find_task_by_pid(pid);
- if (p != tmp)
- break;
- }
-out_unlock:
- read_unlock(&tasklist_lock);
-
-out:
- return retval;
-}
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 1a2fe0f6e..5ef59004c 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -70,33 +70,6 @@ struct inode_operations proc_file_inode_operations = {
NULL /* revalidate */
};
-/*
- * compatibility to replace fs/proc/net.c
- */
-struct inode_operations proc_net_inode_operations = {
- &proc_file_operations, /* default net file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
diff --git a/fs/proc/inode-alloc.txt b/fs/proc/inode-alloc.txt
index 440d3baf8..4af79966c 100644
--- a/fs/proc/inode-alloc.txt
+++ b/fs/proc/inode-alloc.txt
@@ -1,50 +1,14 @@
-Inode allocations in the proc-fs (hex-numbers):
+Current inode allocations in the proc-fs (hex-numbers):
00000000 reserved
- 00000001-00000fff static entries
+ 00000001-00000fff static entries (goners)
001 root-ino
- 002 load-avg
- 003 uptime
- ...
- 080 net/*
- ...
- 100 scsi/*
- ...
- xxx mca/*
- ...
- yyy bus/*
- ...
- fff end
00001000-00001fff dynamic entries
-
00002000-00002fff openprom entries
-
0001xxxx-7fffxxxx pid-dir entries for pid 1-7fff
- 0000 unused
- 0001 unused
- 0002 pid
- 0003 pid/status
- ...
- 0008 pid/fd
- ...
- 00xx-00ff unused
- 01xx pid/fd/* for fd 0-ff
- ...
- 01ff end
- 0200-ffff unused
-
80000000-ffffffff unused
-
-
-New allocation:
-
- 00000000-0000ffff unchanged
-
- 0001xxxx-7fffxxxx pid-dir entries for pid 1-7fff
- 0000-00ff unchanged
- 0100-7fff unused
- 8000-ffff pid/fd/* for fd 0-7fff
-
- 80000000-ffffffff unchanged
+Goal:
+ a) once we'll split the thing into several virtual filesystems we
+ will get rid of magical ranges (and this file, BTW).
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index a5596e4ee..8842cc253 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -14,6 +14,7 @@
#include <linux/locks.h>
#include <linux/limits.h>
#include <linux/config.h>
+#include <linux/module.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -51,9 +52,7 @@ void de_put(struct proc_dir_entry *de)
static void proc_put_inode(struct inode *inode)
{
#ifdef CONFIG_SUN_OPENPROMFS_MODULE
- if ((inode->i_ino >= PROC_OPENPROM_FIRST) &&
- (inode->i_ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM) &&
- proc_openprom_use)
+ if (PROC_INODE_OPENPROM(inode) && proc_openprom_use)
(*proc_openprom_use)(inode, 0);
#endif
/*
@@ -71,18 +70,16 @@ static void proc_delete_inode(struct inode *inode)
{
struct proc_dir_entry *de = inode->u.generic_ip;
-#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
- if ((inode->i_ino >= PROC_OPENPROM_FIRST) &&
- (inode->i_ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM))
+ if (PROC_INODE_PROPER(inode)) {
+ proc_pid_delete_inode(inode);
+ return;
+ }
+ if (PROC_INODE_OPENPROM(inode))
return;
-#endif
if (de) {
- /*
- * Call the fill_inode hook to release module counts.
- */
- if (de->fill_inode)
- de->fill_inode(inode, 0);
+ if (de->owner)
+ __MOD_DEC_USE_COUNT(de->owner);
de_put(de);
}
}
@@ -142,113 +139,6 @@ static int parse_options(char *options,uid_t *uid,gid_t *gid)
return 1;
}
-/*
- * The standard rules, copied from fs/namei.c:permission().
- */
-static int standard_permission(struct inode *inode, int mask)
-{
- int mode = inode->i_mode;
-
- if ((mask & S_IWOTH) && IS_RDONLY(inode) &&
- (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
- return -EROFS; /* Nobody gets write access to a read-only fs */
- else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
- return -EACCES; /* Nobody gets write access to an immutable file */
- else if (current->fsuid == inode->i_uid)
- mode >>= 6;
- else if (in_group_p(inode->i_gid))
- mode >>= 3;
- if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE))
- return 0;
- /* read and search access */
- if ((mask == S_IROTH) ||
- (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH))))
- if (capable(CAP_DAC_READ_SEARCH))
- return 0;
- return -EACCES;
-}
-
-/*
- * Set up permission rules for processes looking at other processes.
- * You're not allowed to see a process unless it has the same or more
- * restricted root than your own. This prevents a chrooted processes
- * from escaping through the /proc entries of less restricted
- * processes, and thus allows /proc to be safely mounted in a chrooted
- * area.
- *
- * Note that root (uid 0) doesn't get permission for this either,
- * since chroot is stronger than root.
- *
- * XXX TODO: use the dentry mechanism to make off-limits procs simply
- * invisible rather than denied? Does each namespace root get its own
- * dentry tree?
- *
- * This also applies the default permissions checks, as it only adds
- * restrictions.
- *
- * Jeremy Fitzhardinge <jeremy@zip.com.au>
- */
-int proc_permission(struct inode *inode, int mask)
-{
- struct task_struct *p;
- unsigned long ino = inode->i_ino;
- unsigned long pid;
- struct dentry *de, *base;
-
- if (standard_permission(inode, mask) != 0)
- return -EACCES;
-
- /*
- * Find the root of the processes being examined (if any).
- * XXX Surely there's a better way of doing this?
- */
- if (ino >= PROC_OPENPROM_FIRST &&
- ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM)
- return 0; /* already allowed */
-
- pid = ino >> 16;
- if (pid == 0)
- return 0; /* already allowed */
-
- de = NULL;
- base = current->fs->root;
-
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
-
- if (p && p->fs)
- de = p->fs->root;
- read_unlock(&tasklist_lock); /* FIXME! */
-
- if (p == NULL)
- return -EACCES; /* ENOENT? */
-
- if (de == NULL)
- {
- /* kswapd and bdflush don't have proper root or cwd... */
- return -EACCES;
- }
-
- /* XXX locking? */
- for(;;)
- {
- struct dentry *parent;
-
- if (de == base)
- return 0; /* already allowed */
-
- de = de->d_covers;
- parent = de->d_parent;
-
- if (de == parent)
- break;
-
- de = parent;
- }
-
- return -EACCES; /* incompatible roots */
-}
-
struct inode * proc_get_inode(struct super_block * sb, int ino,
struct proc_dir_entry * de)
{
@@ -269,14 +159,9 @@ printk("proc_iget: using deleted entry %s, count=%d\n", de->name, de->count);
goto out_fail;
#ifdef CONFIG_SUN_OPENPROMFS_MODULE
- if ((inode->i_ino >= PROC_OPENPROM_FIRST)
- && (inode->i_ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM)
- && proc_openprom_use)
+ if (PROC_INODE_OPENPROM(inode) && proc_openprom_use)
(*proc_openprom_use)(inode, 1);
#endif
- /* N.B. How can this test ever fail?? */
- if (inode->i_sb != sb)
- printk("proc_get_inode: inode fubar\n");
inode->u.generic_ip = (void *) de;
if (de) {
@@ -291,12 +176,8 @@ printk("proc_iget: using deleted entry %s, count=%d\n", de->name, de->count);
inode->i_op = de->ops;
if (de->nlink)
inode->i_nlink = de->nlink;
- /*
- * The fill_inode routine should use this call
- * to increment module counts, if necessary.
- */
- if (de->fill_inode)
- de->fill_inode(inode, 1);
+ if (de->owner)
+ __MOD_INC_USE_COUNT(de->owner);
}
/*
* Fixup the root inode's nlink value
@@ -366,63 +247,7 @@ int proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
void proc_read_inode(struct inode * inode)
{
- unsigned long ino, pid;
- struct task_struct * p;
-
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_blocks = 0;
- inode->i_blksize = 1024;
- ino = inode->i_ino;
- if (ino >= PROC_OPENPROM_FIRST &&
- ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM)
- goto out;
- inode->i_op = NULL;
- inode->i_mode = 0;
- inode->i_uid = 0;
- inode->i_gid = 0;
- inode->i_nlink = 1;
- inode->i_size = 0;
-
- pid = ino >> 16;
- if (!pid)
- goto out;
-
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (!p)
- goto out_unlock;
-
- ino &= 0x0000ffff;
- if (ino == PROC_PID_INO || p->dumpable) {
- inode->i_uid = p->euid;
- inode->i_gid = p->egid;
- }
- if (ino & PROC_PID_FD_DIR) {
- struct file * file;
- ino &= 0x7fff;
- if (!p->files) /* can we ever get here if that's the case? */
- goto out_unlock;
- read_lock(&p->files->file_lock);
- file = fcheck_task(p, ino);
- if (!file)
- goto out_unlock2;
-
- inode->i_op = &proc_link_inode_operations;
- inode->i_size = 64;
- inode->i_mode = S_IFLNK;
- if (file->f_mode & 1)
- inode->i_mode |= S_IRUSR | S_IXUSR;
- if (file->f_mode & 2)
- inode->i_mode |= S_IWUSR | S_IXUSR;
-out_unlock2:
- read_unlock(&p->files->file_lock);
- }
-out_unlock:
- /* Defer unlocking until we're done with the task */
- read_unlock(&tasklist_lock);
-
-out:
- return;
}
void proc_write_inode(struct inode * inode)
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
new file mode 100644
index 000000000..ec2a92db3
--- /dev/null
+++ b/fs/proc/kcore.c
@@ -0,0 +1,388 @@
+/*
+ * fs/proc/kcore.c kernel ELF/AOUT core dumper
+ *
+ * Modelled on fs/exec.c:aout_core_dump()
+ * Jeremy Fitzhardinge <jeremy@sw.oz.au>
+ * Implemented by David Howells <David.Howells@nexor.co.uk>
+ * Modified and incorporated into 2.3.x by Tigran Aivazian <tigran@sco.com>
+ * Support to dump vmalloc'd data structures (ELF only), Tigran Aivazian <tigran@sco.com>
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/elf.h>
+#include <linux/elfcore.h>
+#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+
+
+static int open_kcore(struct inode * inode, struct file * filp)
+{
+ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
+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
+};
+
+struct inode_operations proc_kcore_inode_operations = {
+ &proc_kcore_operations,
+};
+
+#ifdef CONFIG_KCORE_AOUT
+static ssize_t read_kcore(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned long long p = *ppos, memsize;
+ ssize_t read;
+ ssize_t count1;
+ char * pnt;
+ struct user dump;
+#if defined (__i386__) || defined (__mc68000__)
+# define FIRST_MAPPED PAGE_SIZE /* we don't have page 0 mapped on x86.. */
+#else
+# define FIRST_MAPPED 0
+#endif
+
+ memset(&dump, 0, sizeof(struct user));
+ dump.magic = CMAGIC;
+ dump.u_dsize = max_mapnr;
+#if defined (__i386__)
+ dump.start_code = PAGE_OFFSET;
+#endif
+#ifdef __alpha__
+ dump.start_data = PAGE_OFFSET;
+#endif
+
+ memsize = (max_mapnr + 1) << PAGE_SHIFT;
+ if (p >= memsize)
+ return 0;
+ if (count > memsize - p)
+ count = memsize - p;
+ read = 0;
+
+ if (p < sizeof(struct user) && count > 0) {
+ count1 = count;
+ if (p + count1 > sizeof(struct user))
+ count1 = sizeof(struct user)-p;
+ pnt = (char *) &dump + p;
+ copy_to_user(buf,(void *) pnt, count1);
+ buf += count1;
+ p += count1;
+ count -= count1;
+ read += count1;
+ }
+
+ if (count > 0 && p < PAGE_SIZE + FIRST_MAPPED) {
+ count1 = PAGE_SIZE + FIRST_MAPPED - p;
+ if (count1 > count)
+ count1 = count;
+ clear_user(buf, count1);
+ buf += count1;
+ p += count1;
+ count -= count1;
+ read += count1;
+ }
+ if (count > 0) {
+ copy_to_user(buf, (void *) (PAGE_OFFSET+p-PAGE_SIZE), count);
+ read += count;
+ }
+ *ppos += read;
+ return read;
+}
+#else /* CONFIG_KCORE_AOUT */
+
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+
+/* An ELF note in memory */
+struct memelfnote
+{
+ const char *name;
+ int type;
+ unsigned int datasz;
+ void *data;
+};
+
+extern char saved_command_line[];
+
+static size_t get_kcore_size(int *num_vma, int *elf_buflen)
+{
+ size_t try, size = 0;
+ struct vm_struct *m;
+
+ *num_vma = 0;
+ if (!vmlist) {
+ *elf_buflen = PAGE_SIZE;
+ return ((size_t)high_memory - PAGE_OFFSET + PAGE_SIZE);
+ }
+
+ for (m=vmlist; m; m=m->next) {
+ try = (size_t)m->addr + m->size;
+ if (try > size)
+ size = try;
+ *num_vma = *num_vma + 1;
+ }
+ *elf_buflen = sizeof(struct elfhdr) +
+ (*num_vma + 2)*sizeof(struct elf_phdr) +
+ 3 * sizeof(struct memelfnote);
+ *elf_buflen = PAGE_ALIGN(*elf_buflen);
+ return (size - PAGE_OFFSET + *elf_buflen);
+}
+
+
+/*****************************************************************************/
+/*
+ * determine size of ELF note
+ */
+static int notesize(struct memelfnote *en)
+{
+ int sz;
+
+ sz = sizeof(struct elf_note);
+ sz += roundup(strlen(en->name), 4);
+ sz += roundup(en->datasz, 4);
+
+ return sz;
+} /* end notesize() */
+
+/*****************************************************************************/
+/*
+ * store a note in the header buffer
+ */
+static char *storenote(struct memelfnote *men, char *bufp)
+{
+ struct elf_note en;
+
+#define DUMP_WRITE(addr,nr) do { memcpy(bufp,addr,nr); bufp += nr; } while(0)
+
+ en.n_namesz = strlen(men->name);
+ en.n_descsz = men->datasz;
+ en.n_type = men->type;
+
+ DUMP_WRITE(&en, sizeof(en));
+ DUMP_WRITE(men->name, en.n_namesz);
+
+ /* XXX - cast from long long to long to avoid need for libgcc.a */
+ bufp = (char*) roundup((unsigned long)bufp,4);
+ DUMP_WRITE(men->data, men->datasz);
+ bufp = (char*) roundup((unsigned long)bufp,4);
+
+#undef DUMP_WRITE
+
+ return bufp;
+} /* end storenote() */
+
+/*
+ * store an ELF coredump header in the supplied buffer
+ * num_vma is the number of elements in vmlist
+ */
+static void elf_kcore_store_hdr(char *bufp, int num_vma, int elf_buflen)
+{
+ struct elf_prstatus prstatus; /* NT_PRSTATUS */
+ struct elf_prpsinfo prpsinfo; /* NT_PRPSINFO */
+ struct elf_phdr *nhdr, *phdr;
+ struct elfhdr *elf;
+ struct memelfnote notes[3];
+ off_t offset = 0;
+ struct vm_struct *m;
+
+ /* setup ELF header */
+ elf = (struct elfhdr *) bufp;
+ bufp += sizeof(struct elfhdr);
+ offset += sizeof(struct elfhdr);
+ memcpy(elf->e_ident, ELFMAG, SELFMAG);
+ elf->e_ident[EI_CLASS] = ELF_CLASS;
+ elf->e_ident[EI_DATA] = ELF_DATA;
+ elf->e_ident[EI_VERSION]= EV_CURRENT;
+ memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+ elf->e_type = ET_CORE;
+ elf->e_machine = ELF_ARCH;
+ elf->e_version = EV_CURRENT;
+ elf->e_entry = 0;
+ elf->e_phoff = sizeof(struct elfhdr);
+ elf->e_shoff = 0;
+ elf->e_flags = 0;
+ elf->e_ehsize = sizeof(struct elfhdr);
+ elf->e_phentsize= sizeof(struct elf_phdr);
+ elf->e_phnum = 2 + num_vma;
+ elf->e_shentsize= 0;
+ elf->e_shnum = 0;
+ elf->e_shstrndx = 0;
+
+ /* setup ELF PT_NOTE program header */
+ nhdr = (struct elf_phdr *) bufp;
+ bufp += sizeof(struct elf_phdr);
+ offset += sizeof(struct elf_phdr);
+ nhdr->p_type = PT_NOTE;
+ nhdr->p_offset = 0;
+ nhdr->p_vaddr = 0;
+ nhdr->p_paddr = 0;
+ nhdr->p_filesz = 0;
+ nhdr->p_memsz = 0;
+ nhdr->p_flags = 0;
+ nhdr->p_align = 0;
+
+ /* setup ELF PT_LOAD program header */
+ phdr = (struct elf_phdr *) bufp;
+ bufp += sizeof(struct elf_phdr);
+ offset += sizeof(struct elf_phdr);
+ phdr->p_type = PT_LOAD;
+ phdr->p_flags = PF_R|PF_W|PF_X;
+ phdr->p_offset = elf_buflen;
+ phdr->p_vaddr = PAGE_OFFSET;
+ phdr->p_paddr = __pa(PAGE_OFFSET);
+ phdr->p_filesz = phdr->p_memsz = ((unsigned long)high_memory - PAGE_OFFSET);
+ phdr->p_align = PAGE_SIZE;
+
+ for (m=vmlist; m; m=m->next) {
+ phdr = (struct elf_phdr *) bufp;
+ bufp += sizeof(struct elf_phdr);
+ offset += sizeof(struct elf_phdr);
+
+ phdr->p_type = PT_LOAD;
+ phdr->p_flags = PF_R|PF_W|PF_X;
+ phdr->p_offset = (size_t)m->addr - PAGE_OFFSET + elf_buflen;
+ phdr->p_vaddr = (size_t)m->addr;
+ phdr->p_paddr = __pa(m);
+ phdr->p_filesz = phdr->p_memsz = m->size;
+ phdr->p_align = PAGE_SIZE;
+ }
+
+ /*
+ * Set up the notes in similar form to SVR4 core dumps made
+ * with info from their /proc.
+ */
+ nhdr->p_offset = offset;
+
+ /* set up the process status */
+ notes[0].name = "CORE";
+ notes[0].type = NT_PRSTATUS;
+ notes[0].datasz = sizeof(struct elf_prstatus);
+ notes[0].data = &prstatus;
+
+ memset(&prstatus, 0, sizeof(struct elf_prstatus));
+
+ nhdr->p_filesz = notesize(&notes[0]);
+ bufp = storenote(&notes[0], bufp);
+
+ /* set up the process info */
+ notes[1].name = "CORE";
+ notes[1].type = NT_PRPSINFO;
+ notes[1].datasz = sizeof(struct elf_prpsinfo);
+ notes[1].data = &prpsinfo;
+
+ memset(&prpsinfo, 0, sizeof(struct elf_prpsinfo));
+ prpsinfo.pr_state = 0;
+ prpsinfo.pr_sname = 'R';
+ prpsinfo.pr_zomb = 0;
+
+ strcpy(prpsinfo.pr_fname, "vmlinux");
+ strncpy(prpsinfo.pr_psargs, saved_command_line, ELF_PRARGSZ);
+
+ nhdr->p_filesz = notesize(&notes[1]);
+ bufp = storenote(&notes[1], bufp);
+
+ /* set up the task structure */
+ notes[2].name = "CORE";
+ notes[2].type = NT_TASKSTRUCT;
+ notes[2].datasz = sizeof(struct task_struct);
+ notes[2].data = current;
+
+ nhdr->p_filesz = notesize(&notes[2]);
+ bufp = storenote(&notes[2], bufp);
+
+} /* end elf_kcore_store_hdr() */
+
+/*****************************************************************************/
+/*
+ * read from the ELF header and then kernel memory
+ */
+static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen,
+ loff_t *fpos)
+{
+ ssize_t acc = 0;
+ size_t size, tsz;
+ char * elf_buffer;
+ int elf_buflen = 0, num_vma = 0;
+
+ /* XXX we need to somehow lock vmlist between here
+ * and after elf_kcore_store_hdr() returns.
+ * For now assume that num_vma does not change (TA)
+ */
+ proc_root_kcore.size = size = get_kcore_size(&num_vma, &elf_buflen);
+ if (buflen == 0 || *fpos >= size)
+ return 0;
+
+ /* trim buflen to not go beyond EOF */
+ if (buflen > size - *fpos)
+ buflen = size - *fpos;
+
+ /* construct an ELF core header if we'll need some of it */
+ if (*fpos < elf_buflen) {
+ tsz = elf_buflen - *fpos;
+ if (buflen < tsz)
+ tsz = buflen;
+ elf_buffer = kmalloc(elf_buflen, GFP_KERNEL);
+ if (!elf_buffer)
+ return -ENOMEM;
+ memset(elf_buffer, 0, elf_buflen);
+ elf_kcore_store_hdr(elf_buffer, num_vma, elf_buflen);
+ copy_to_user(buffer, elf_buffer, tsz);
+ kfree(elf_buffer);
+ buflen -= tsz;
+ *fpos += tsz;
+ buffer += tsz;
+ acc += tsz;
+
+ /* leave now if filled buffer already */
+ if (buflen == 0)
+ return tsz;
+ }
+
+ /* where page 0 not mapped, write zeros into buffer */
+#if defined (__i386__) || defined (__mc68000__)
+ if (*fpos < PAGE_SIZE + elf_buflen) {
+ /* work out how much to clear */
+ tsz = PAGE_SIZE + elf_buflen - *fpos;
+ if (buflen < tsz)
+ tsz = buflen;
+
+ /* write zeros to buffer */
+ clear_user(buffer, tsz);
+ buflen -= tsz;
+ *fpos += tsz;
+ buffer += tsz;
+ acc += tsz;
+
+ /* leave now if filled buffer already */
+ if (buflen == 0)
+ return tsz;
+ }
+#endif
+
+ /* fill the remainder of the buffer from kernel VM space */
+#if defined (__i386__) || defined (__mc68000__)
+ copy_to_user(buffer, __va(*fpos - PAGE_SIZE), buflen);
+#else
+ copy_to_user(buffer, __va(*fpos), buflen);
+#endif
+ acc += buflen;
+ *fpos += buflen;
+
+ return acc;
+
+}
+#endif /* CONFIG_KCORE_AOUT */
diff --git a/fs/proc/link.c b/fs/proc/link.c
deleted file mode 100644
index 69d435600..000000000
--- a/fs/proc/link.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * linux/fs/proc/link.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * /proc link-file handling code
- */
-
-#include <asm/uaccess.h>
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-
-static int proc_readlink(struct dentry *, char *, int);
-static struct dentry * proc_follow_link(struct dentry *, struct dentry *, unsigned int);
-
-/*
- * links can't do much...
- */
-static struct file_operations proc_fd_link_operations = {
- NULL, /* lseek - default */
- NULL, /* read - bad */
- NULL, /* write - bad */
- NULL, /* readdir - bad */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* very special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-struct inode_operations proc_link_inode_operations = {
- &proc_fd_link_operations,/* file-operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- proc_readlink, /* readlink */
- proc_follow_link, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- proc_permission, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-static struct dentry * proc_follow_link(struct dentry *dentry,
- struct dentry *base,
- unsigned int follow)
-{
- struct inode *inode = dentry->d_inode;
- struct task_struct *p;
- struct dentry * result;
- int ino, pid;
- int error;
-
- /* We don't need a base pointer in the /proc filesystem */
- dput(base);
-
- error = permission(inode, MAY_EXEC);
- result = ERR_PTR(error);
- if (error)
- goto out;
-
- ino = inode->i_ino;
- pid = ino >> 16;
- ino &= 0x0000ffff;
-
- result = ERR_PTR(-ENOENT);
-
- switch (ino) {
- case PROC_PID_CWD:
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (p && p->fs && p->fs->pwd)
- result = dget(p->fs->pwd);
- read_unlock(&tasklist_lock);
- break;
-
- case PROC_PID_ROOT:
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (p && p->fs && p->fs->root)
- result = dget(p->fs->root);
- read_unlock(&tasklist_lock);
- break;
-
- case PROC_PID_EXE: {
- struct mm_struct *mm = NULL;
- struct vm_area_struct * vma;
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (p)
- mm = p->mm;
- if (mm)
- atomic_inc(&mm->mm_users);
- read_unlock(&tasklist_lock);
- if (!mm)
- break;
- down(&mm->mmap_sem);
- vma = mm->mmap;
- while (vma) {
- if ((vma->vm_flags & VM_EXECUTABLE) &&
- vma->vm_file) {
- result = dget(vma->vm_file->f_dentry);
- break;
- }
- vma = vma->vm_next;
- }
- up(&mm->mmap_sem);
- mmput(mm);
- break;
- }
- default:
- if (ino & PROC_PID_FD_DIR) {
- struct file * file;
- struct files_struct *files = NULL;
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- if (p)
- files = p->files;
- read_unlock(&tasklist_lock);
- if (!files)
- break;
- ino &= 0x7fff;
- read_lock(&files->file_lock);
- /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
- if (ino < files->max_fds &&
- (file = files->fd[ino]) && file->f_dentry)
- result = dget(file->f_dentry);
- read_unlock(&p->files->file_lock);
- }
- }
-out:
- return result;
-}
-
-/*
- * This pretty-prints the pathname of a dentry,
- * clarifying sockets etc.
- */
-static int do_proc_readlink(struct dentry *dentry, char * buffer, int buflen)
-{
- struct inode * inode;
- char * tmp = (char*)__get_free_page(GFP_KERNEL), *path, *pattern;
- int len;
-
- if(tmp==NULL)
- return -ENOMEM;
-
- /* Check for special dentries.. */
- pattern = NULL;
- inode = dentry->d_inode;
- if (inode && IS_ROOT(dentry)) {
- if (S_ISSOCK(inode->i_mode))
- pattern = "socket:[%lu]";
- if (S_ISFIFO(inode->i_mode))
- pattern = "pipe:[%lu]";
- }
-
- if (pattern) {
- len = sprintf(tmp, pattern, inode->i_ino);
- path = tmp;
- } else {
- path = d_path(dentry, tmp, PAGE_SIZE);
- len = tmp + PAGE_SIZE - 1 - path;
- }
-
- if (len < buflen)
- buflen = len;
- dput(dentry);
- copy_to_user(buffer, path, buflen);
- free_page((unsigned long)tmp);
- return buflen;
-}
-
-static int proc_readlink(struct dentry * dentry, char * buffer, int buflen)
-{
- int error;
-
- dentry = proc_follow_link(dentry, NULL, 1);
- error = PTR_ERR(dentry);
- if (!IS_ERR(dentry)) {
- error = -ENOENT;
- if (dentry) {
- error = do_proc_readlink(dentry, buffer, buflen);
- }
- }
- return error;
-}
diff --git a/fs/proc/mem.c b/fs/proc/mem.c
deleted file mode 100644
index 90cd79722..000000000
--- a/fs/proc/mem.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * linux/fs/proc/mem.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/proc_fs.h>
-#include <linux/highmem.h>
-
-#include <asm/page.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-
-/*
- * mem_write isn't really a good idea right now. It needs
- * to check a lot more: if the process we try to write to
- * dies in the middle right now, mem_write will overwrite
- * kernel memory.. This disables it altogether.
- */
-#define mem_write NULL
-
-static int check_range(struct mm_struct * mm, unsigned long addr, int count)
-{
- struct vm_area_struct *vma;
- int retval;
-
- vma = find_vma(mm, addr);
- if (!vma)
- return -EACCES;
- if (vma->vm_start > addr)
- return -EACCES;
- if (!(vma->vm_flags & VM_READ))
- return -EACCES;
- while ((retval = vma->vm_end - addr) < count) {
- struct vm_area_struct *next = vma->vm_next;
- if (!next)
- break;
- if (vma->vm_end != next->vm_start)
- break;
- if (!(next->vm_flags & VM_READ))
- break;
- vma = next;
- }
- if (retval > count)
- retval = count;
- return retval;
-}
-
-static struct task_struct * get_task(int pid)
-{
- struct task_struct * tsk = current;
-
- if (pid != tsk->pid) {
- tsk = find_task_by_pid(pid);
-
- /* Allow accesses only under the same circumstances
- * that we would allow ptrace to work.
- */
- if (tsk) {
- if (!(tsk->flags & PF_PTRACED)
- || tsk->state != TASK_STOPPED
- || tsk->p_pptr != current)
- tsk = NULL;
- }
- }
- return tsk;
-}
-
-static ssize_t mem_read(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- pgd_t *page_dir;
- pmd_t *page_middle;
- pte_t pte;
- struct page * page;
- struct task_struct * tsk;
- unsigned long addr;
- unsigned long maddr; /* temporary mapped address */
- char *tmp;
- ssize_t scount, i;
-
- read_lock(&tasklist_lock);
- tsk = get_task(inode->i_ino >> 16);
- read_unlock(&tasklist_lock); /* FIXME: This should really be done only afetr not using tsk any more!!! */
- if (!tsk)
- return -ESRCH;
- addr = *ppos;
- scount = check_range(tsk->mm, addr, count);
- if (scount < 0)
- return scount;
- tmp = buf;
- while (scount > 0) {
- if (signal_pending(current))
- break;
- page_dir = pgd_offset(tsk->mm,addr);
- if (pgd_none(*page_dir))
- break;
- if (pgd_bad(*page_dir)) {
- pgd_ERROR(*page_dir);
- pgd_clear(page_dir);
- break;
- }
- page_middle = pmd_offset(page_dir,addr);
- if (pmd_none(*page_middle))
- break;
- if (pmd_bad(*page_middle)) {
- pmd_ERROR(*page_middle);
- pmd_clear(page_middle);
- break;
- }
- pte = *pte_offset(page_middle,addr);
- if (!pte_present(pte))
- break;
- page = pte_page(pte);
- i = PAGE_SIZE-(addr & ~PAGE_MASK);
- if (i > scount)
- i = scount;
- maddr = kmap(page, KM_READ);
- copy_to_user(tmp, (char *)maddr + (addr & ~PAGE_MASK), i);
- kunmap(maddr, KM_READ);
- addr += i;
- tmp += i;
- scount -= i;
- }
- *ppos = addr;
- return tmp-buf;
-}
-
-#ifndef mem_write
-
-static ssize_t mem_write(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- pgd_t *page_dir;
- pmd_t *page_middle;
- pte_t pte;
- struct page * page;
- struct task_struct * tsk;
- unsigned long addr;
- unsigned long maddr; /* temporary mapped address */
- char *tmp;
- long i;
-
- addr = *ppos;
- tsk = get_task(inode->i_ino >> 16);
- if (!tsk)
- return -ESRCH;
- tmp = buf;
- while (count > 0) {
- if (signal_pending(current))
- break;
- page_dir = pgd_offset(tsk,addr);
- if (pgd_none(*page_dir))
- break;
- if (pgd_bad(*page_dir)) {
- pgd_ERROR(*page_dir);
- pgd_clear(page_dir);
- break;
- }
- page_middle = pmd_offset(page_dir,addr);
- if (pmd_none(*page_middle))
- break;
- if (pmd_bad(*page_middle)) {
- pmd_ERROR(*page_middle);
- pmd_clear(page_middle);
- break;
- }
- pte = *pte_offset(page_middle,addr);
- if (!pte_present(pte))
- break;
- if (!pte_write(pte))
- break;
- page = pte_page(pte);
- i = PAGE_SIZE-(addr & ~PAGE_MASK);
- if (i > count)
- i = count;
- maddr = kmap(page, KM_WRITE);
- copy_from_user((char *)maddr + (addr & ~PAGE_MASK), tmp, i);
- kunmap(maddr, KM_WRITE);
- addr += i;
- tmp += i;
- count -= i;
- }
- *ppos = addr;
- if (tmp != buf)
- return tmp-buf;
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-#endif
-
-static long long mem_lseek(struct file * file, long long offset, int orig)
-{
- switch (orig) {
- case 0:
- file->f_pos = offset;
- return file->f_pos;
- case 1:
- file->f_pos += offset;
- return file->f_pos;
- default:
- return -EINVAL;
- }
-}
-
-/*
- * This isn't really reliable by any means..
- */
-int mem_mmap(struct file * file, struct vm_area_struct * vma)
-{
- struct task_struct *tsk;
- pgd_t *src_dir, *dest_dir;
- pmd_t *src_middle, *dest_middle;
- pte_t *src_table, *dest_table;
- unsigned long stmp, dtmp, mapnr;
- struct vm_area_struct *src_vma = NULL;
- struct inode *inode = file->f_dentry->d_inode;
-
- /* Get the source's task information */
-
- tsk = get_task(inode->i_ino >> 16);
-
- if (!tsk)
- return -ESRCH;
-
- /* Ensure that we have a valid source area. (Has to be mmap'ed and
- have valid page information.) We can't map shared memory at the
- moment because working out the vm_area_struct & nattach stuff isn't
- worth it. */
-
- src_vma = tsk->mm->mmap;
- stmp = vma->vm_offset;
- while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) {
- while (src_vma && stmp > src_vma->vm_end)
- src_vma = src_vma->vm_next;
- if (!src_vma || (src_vma->vm_flags & VM_SHM))
- return -EINVAL;
-
- src_dir = pgd_offset(tsk->mm, stmp);
- if (pgd_none(*src_dir))
- return -EINVAL;
- if (pgd_bad(*src_dir)) {
- pgd_ERROR(*src_dir);
- return -EINVAL;
- }
- src_middle = pmd_offset(src_dir, stmp);
- if (pmd_none(*src_middle))
- return -EINVAL;
- if (pmd_bad(*src_middle)) {
- pmd_ERROR(*src_middle);
- return -EINVAL;
- }
- src_table = pte_offset(src_middle, stmp);
- if (pte_none(*src_table))
- return -EINVAL;
-
- if (stmp < src_vma->vm_start) {
- if (!(src_vma->vm_flags & VM_GROWSDOWN))
- return -EINVAL;
- if (src_vma->vm_end - stmp > current->rlim[RLIMIT_STACK].rlim_cur)
- return -EINVAL;
- }
- stmp += PAGE_SIZE;
- }
-
- src_vma = tsk->mm->mmap;
- stmp = vma->vm_offset;
- dtmp = vma->vm_start;
-
- flush_cache_range(vma->vm_mm, vma->vm_start, vma->vm_end);
- flush_cache_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end);
- while (dtmp < vma->vm_end) {
- while (src_vma && stmp > src_vma->vm_end)
- src_vma = src_vma->vm_next;
-
- src_dir = pgd_offset(tsk->mm, stmp);
- src_middle = pmd_offset(src_dir, stmp);
- src_table = pte_offset(src_middle, stmp);
-
- dest_dir = pgd_offset(current->mm, dtmp);
- dest_middle = pmd_alloc(dest_dir, dtmp);
- if (!dest_middle)
- return -ENOMEM;
- dest_table = pte_alloc(dest_middle, dtmp);
- if (!dest_table)
- return -ENOMEM;
-
- if (!pte_present(*src_table))
- handle_mm_fault(tsk, src_vma, stmp, 1);
-
- if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table))
- handle_mm_fault(tsk, src_vma, stmp, 1);
-
- set_pte(src_table, pte_mkdirty(*src_table));
- set_pte(dest_table, *src_table);
- mapnr = pte_pagenr(*src_table);
- if (mapnr < max_mapnr)
- get_page(mem_map + pte_pagenr(*src_table));
-
- stmp += PAGE_SIZE;
- dtmp += PAGE_SIZE;
- }
-
- flush_tlb_range(vma->vm_mm, vma->vm_start, vma->vm_end);
- flush_tlb_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end);
- return 0;
-}
-
-static struct file_operations proc_mem_operations = {
- mem_lseek,
- mem_read,
- mem_write,
- NULL, /* mem_readdir */
- NULL, /* mem_poll */
- NULL, /* mem_ioctl */
- mem_mmap, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-struct inode_operations proc_mem_inode_operations = {
- &proc_mem_operations, /* default base directory file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- proc_permission, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
diff --git a/fs/proc/net.c b/fs/proc/net.c
deleted file mode 100644
index b4e18bc49..000000000
--- a/fs/proc/net.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * linux/fs/proc/net.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * gjh 3/'93 heim@peanuts.informatik.uni-tuebingen.de (Gerald J. Heim)
- * most of this file is stolen from base.c
- * it works, but you shouldn't use it as a guideline
- * for new proc-fs entries. once i'll make it better.
- * fvk 3/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
- * cleaned up the whole thing, moved "net" specific code to
- * the NET kernel layer (where it belonged in the first place).
- * Michael K. Johnson (johnsonm@stolaf.edu) 3/93
- * Added support from my previous inet.c. Cleaned things up
- * quite a bit, modularized the code.
- * fvk 4/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen)
- * Renamed "route_get_info()" to "rt_get_info()" for consistency.
- * Alan Cox (gw4pts@gw4pts.ampr.org) 4/94
- * Dusted off the code and added IPX. Fixed the 4K limit.
- * Erik Schoenfelder (schoenfr@ibr.cs.tu-bs.de)
- * /proc/net/snmp.
- * Alan Cox (gw4pts@gw4pts.ampr.org) 1/95
- * Added AppleTalk slots
- *
- * proc net directory handling functions
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-
-#include <asm/uaccess.h>
-
-#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
-
-static long proc_readnet(struct inode * inode, struct file * file,
- char * buf, unsigned long count)
-{
- char * page;
- int bytes=count;
- int copied=0;
- char *start;
- struct proc_dir_entry * dp;
-
- if (count < 0)
- return -EINVAL;
- dp = (struct proc_dir_entry *) inode->u.generic_ip;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
-
- while (bytes>0)
- {
- int length, thistime=bytes;
- if (bytes > PROC_BLOCK_SIZE)
- thistime=PROC_BLOCK_SIZE;
-
- length = dp->get_info(page, &start,
- file->f_pos,
- thistime,
- (file->f_flags & O_ACCMODE) == O_RDWR);
-
- /*
- * We have been given a non page aligned block of
- * the data we asked for + a bit. We have been given
- * the start pointer and we know the length..
- */
-
- if (length <= 0)
- break;
- /*
- * Copy the bytes
- */
- copy_to_user(buf+copied, start, length);
- file->f_pos += length; /* Move down the file */
- bytes -= length;
- copied += length;
- if (length<thistime)
- break; /* End of file */
- }
- free_page((unsigned long) page);
- return copied;
-}
-
-static struct file_operations proc_net_operations = {
- NULL, /* lseek - default */
- proc_readnet, /* read - bad */
- 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 */
-};
-
-/*
- * proc directories can do almost nothing..
- */
-struct inode_operations proc_net_inode_operations = {
- &proc_net_operations, /* default net file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
new file mode 100644
index 000000000..8ea9813a6
--- /dev/null
+++ b/fs/proc/proc_misc.c
@@ -0,0 +1,692 @@
+/*
+ * linux/fs/proc/proc_misc.c
+ *
+ * linux/fs/proc/array.c
+ * Copyright (C) 1992 by Linus Torvalds
+ * based on ideas by Darren Senn
+ *
+ * This used to be the part of array.c. See the rest of history and credits
+ * there. I took this into a separate file and switched the thing to generic
+ * proc_file_inode_operations, leaving in array.c only per-process stuff.
+ * Inumbers allocation made dynamic (via create_proc_entry()). AV, May 1999.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+#include <linux/mman.h>
+#include <linux/proc_fs.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/signal.h>
+#include <linux/module.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+
+#define LOAD_INT(x) ((x) >> FSHIFT)
+#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
+/*
+ * Warning: stuff below (imported functions) assumes that its output will fit
+ * into one page. For some of those functions it may be wrong. Moreover, we
+ * have a way to deal with that gracefully. Right now I used straightforward
+ * wrappers, but this needs further analysis wrt potential overflows.
+ */
+extern int get_cpuinfo(char *);
+extern int get_hardware_list(char *);
+extern int get_stram_list(char *);
+#ifdef CONFIG_DEBUG_MALLOC
+extern int get_malloc(char * buffer);
+#endif
+#ifdef CONFIG_MODULES
+extern int get_module_list(char *);
+extern int get_ksyms_list(char *, char **, off_t, int);
+#endif
+extern int get_device_list(char *);
+extern int get_partition_list(char *);
+extern int get_filesystem_list(char *);
+extern int get_filesystem_info(char *);
+extern int get_exec_domain_list(char *);
+extern int get_irq_list(char *);
+extern int get_dma_list(char *);
+extern int get_rtc_status (char *);
+extern int get_locks_status (char *, char **, off_t, int);
+extern int get_swaparea_info (char *);
+#ifdef CONFIG_SGI_DS1286
+extern int get_ds1286_status(char *);
+#endif
+
+static int loadavg_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int a, b, c;
+ int len;
+
+ a = avenrun[0] + (FIXED_1/200);
+ b = avenrun[1] + (FIXED_1/200);
+ c = avenrun[2] + (FIXED_1/200);
+ len = sprintf(page,"%d.%02d %d.%02d %d.%02d %d/%d %d\n",
+ LOAD_INT(a), LOAD_FRAC(a),
+ LOAD_INT(b), LOAD_FRAC(b),
+ LOAD_INT(c), LOAD_FRAC(c),
+ nr_running, nr_threads, last_pid);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int uptime_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ unsigned long uptime;
+ unsigned long idle;
+ int len;
+
+ uptime = jiffies;
+ idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
+
+ /* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
+ that would overflow about every five days at HZ == 100.
+ Therefore the identity a = (a / b) * b + a % b is used so that it is
+ calculated as (((t / HZ) * 100) + ((t % HZ) * 100) / HZ) % 100.
+ The part in front of the '+' always evaluates as 0 (mod 100). All divisions
+ in the above formulas are truncating. For HZ being a power of 10, the
+ calculations simplify to the version in the #else part (if the printf
+ format is adapted to the same number of digits as zeroes in HZ.
+ */
+#if HZ!=100
+ len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
+ uptime / HZ,
+ (((uptime % HZ) * 100) / HZ) % 100,
+ idle / HZ,
+ (((idle % HZ) * 100) / HZ) % 100);
+#else
+ len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
+ uptime / HZ,
+ uptime % HZ,
+ idle / HZ,
+ idle % HZ);
+#endif
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int meminfo_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct sysinfo i;
+ int len;
+
+/*
+ * display in kilobytes.
+ */
+#define K(x) ((x) << (PAGE_SHIFT - 10))
+#define B(x) ((x) << PAGE_SHIFT)
+ si_meminfo(&i);
+ si_swapinfo(&i);
+ len = sprintf(page, " total: used: free: shared: buffers: cached:\n"
+ "Mem: %8lu %8lu %8lu %8lu %8lu %8u\n"
+ "Swap: %8lu %8lu %8lu\n",
+ B(i.totalram), B(i.totalram-i.freeram), B(i.freeram),
+ B(i.sharedram), B(i.bufferram),
+ B(atomic_read(&page_cache_size)), B(i.totalswap),
+ B(i.totalswap-i.freeswap), B(i.freeswap));
+ /*
+ * Tagged format, for easy grepping and expansion.
+ * The above will go away eventually, once the tools
+ * have been updated.
+ */
+ len += sprintf(page+len,
+ "MemTotal: %8lu kB\n"
+ "MemFree: %8lu kB\n"
+ "MemShared: %8lu kB\n"
+ "Buffers: %8lu kB\n"
+ "Cached: %8u kB\n"
+ "HighTotal: %8lu kB\n"
+ "HighFree: %8lu kB\n"
+ "LowTotal: %8lu kB\n"
+ "LowFree: %8lu kB\n"
+ "SwapTotal: %8lu kB\n"
+ "SwapFree: %8lu kB\n",
+ K(i.totalram),
+ K(i.freeram),
+ K(i.sharedram),
+ K(i.bufferram),
+ K(atomic_read(&page_cache_size)),
+ K(i.totalhigh),
+ K(i.freehigh),
+ K(i.totalram-i.totalhigh),
+ K(i.freeram-i.freehigh),
+ K(i.totalswap),
+ K(i.freeswap));
+
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+#undef B
+#undef K
+}
+
+static int version_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ extern char *linux_banner;
+ int len;
+
+ strcpy(page, linux_banner);
+ len = strlen(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int cpuinfo_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_cpuinfo(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+#ifdef CONFIG_PROC_HARDWARE
+static int hardware_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_hardware_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+#ifdef CONFIG_STRAM_PROC
+static int stram_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_stram_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+#ifdef CONFIG_DEBUG_MALLOC
+static int malloc_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_malloc(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+#ifdef CONFIG_MODULES
+static int modules_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_module_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int ksyms_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_ksyms_list(page, start, off, count);
+ if (len < count) *eof = 1;
+ return len;
+}
+#endif
+
+static int kstat_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int i, len;
+ unsigned sum = 0;
+ extern unsigned long total_forks;
+ unsigned long jif = jiffies;
+
+ for (i = 0 ; i < NR_IRQS ; i++)
+ sum += kstat_irqs(i);
+
+#ifdef __SMP__
+ len = sprintf(page,
+ "cpu %u %u %u %lu\n",
+ kstat.cpu_user,
+ kstat.cpu_nice,
+ kstat.cpu_system,
+ jif*smp_num_cpus - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system));
+ for (i = 0 ; i < smp_num_cpus; i++)
+ len += sprintf(page + len, "cpu%d %u %u %u %lu\n",
+ i,
+ kstat.per_cpu_user[cpu_logical_map(i)],
+ kstat.per_cpu_nice[cpu_logical_map(i)],
+ kstat.per_cpu_system[cpu_logical_map(i)],
+ jif - ( kstat.per_cpu_user[cpu_logical_map(i)] \
+ + kstat.per_cpu_nice[cpu_logical_map(i)] \
+ + kstat.per_cpu_system[cpu_logical_map(i)]));
+ len += sprintf(page + len,
+ "disk %u %u %u %u\n"
+ "disk_rio %u %u %u %u\n"
+ "disk_wio %u %u %u %u\n"
+ "disk_rblk %u %u %u %u\n"
+ "disk_wblk %u %u %u %u\n"
+ "page %u %u\n"
+ "swap %u %u\n"
+ "intr %u",
+#else
+ len = sprintf(page,
+ "cpu %u %u %u %lu\n"
+ "disk %u %u %u %u\n"
+ "disk_rio %u %u %u %u\n"
+ "disk_wio %u %u %u %u\n"
+ "disk_rblk %u %u %u %u\n"
+ "disk_wblk %u %u %u %u\n"
+ "page %u %u\n"
+ "swap %u %u\n"
+ "intr %u",
+ kstat.cpu_user,
+ kstat.cpu_nice,
+ kstat.cpu_system,
+ jif*smp_num_cpus - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
+#endif
+ kstat.dk_drive[0], kstat.dk_drive[1],
+ kstat.dk_drive[2], kstat.dk_drive[3],
+ kstat.dk_drive_rio[0], kstat.dk_drive_rio[1],
+ kstat.dk_drive_rio[2], kstat.dk_drive_rio[3],
+ kstat.dk_drive_wio[0], kstat.dk_drive_wio[1],
+ kstat.dk_drive_wio[2], kstat.dk_drive_wio[3],
+ kstat.dk_drive_rblk[0], kstat.dk_drive_rblk[1],
+ kstat.dk_drive_rblk[2], kstat.dk_drive_rblk[3],
+ kstat.dk_drive_wblk[0], kstat.dk_drive_wblk[1],
+ kstat.dk_drive_wblk[2], kstat.dk_drive_wblk[3],
+ kstat.pgpgin,
+ kstat.pgpgout,
+ kstat.pswpin,
+ kstat.pswpout,
+ sum);
+ for (i = 0 ; i < NR_IRQS ; i++)
+ len += sprintf(page + len, " %u", kstat_irqs(i));
+ len += sprintf(page + len,
+ "\nctxt %u\n"
+ "btime %lu\n"
+ "processes %lu\n",
+ kstat.context_swtch,
+ xtime.tv_sec - jif / HZ,
+ total_forks);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int devices_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_device_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int partitions_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_partition_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int interrupts_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_irq_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int filesystems_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_filesystem_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int dma_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_dma_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int ioports_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_ioport_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int cmdline_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ extern char saved_command_line[];
+ int len;
+
+ len = sprintf(page, "%s\n", saved_command_line);
+ len = strlen(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+#ifdef CONFIG_RTC
+static int rtc_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_rtc_status(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+#ifdef CONFIG_SGI_DS1286
+static int ds1286_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_ds1286_status(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+#endif
+
+static int locks_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_locks_status(page, start, off, count);
+ if (len < count) *eof = 1;
+ return len;
+}
+
+static int mounts_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_filesystem_info(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int execdomains_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_exec_domain_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int swaps_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_swaparea_info(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int slabinfo_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_slabinfo(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int memory_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = get_mem_list(page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+/*
+ * This function accesses profiling information. The returned data is
+ * binary: the sampling step and the actual contents of the profile
+ * buffer. Use of the program readprofile is recommended in order to
+ * get meaningful info out of these data.
+ */
+static ssize_t read_profile(struct file *file, char *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned long p = *ppos;
+ ssize_t read;
+ char * pnt;
+ unsigned int sample_step = 1 << prof_shift;
+
+ if (p >= (prof_len+1)*sizeof(unsigned int))
+ return 0;
+ if (count > (prof_len+1)*sizeof(unsigned int) - p)
+ count = (prof_len+1)*sizeof(unsigned int) - p;
+ read = 0;
+
+ while (p < sizeof(unsigned int) && count > 0) {
+ put_user(*((char *)(&sample_step)+p),buf);
+ buf++; p++; count--; read++;
+ }
+ pnt = (char *)prof_buffer + p - sizeof(unsigned int);
+ copy_to_user(buf,(void *)pnt,count);
+ read += count;
+ *ppos += read;
+ return read;
+}
+
+/*
+ * Writing to /proc/profile resets the counters
+ *
+ * Writing a 'profiling multiplier' value into it also re-sets the profiling
+ * interrupt frequency, on architectures that support this.
+ */
+static ssize_t write_profile(struct file * file, const char * buf,
+ size_t count, loff_t *ppos)
+{
+#ifdef __SMP__
+ extern int setup_profiling_timer (unsigned int multiplier);
+
+ if (count==sizeof(int)) {
+ unsigned int multiplier;
+
+ if (copy_from_user(&multiplier, buf, sizeof(int)))
+ return -EFAULT;
+
+ if (setup_profiling_timer(multiplier))
+ return -EINVAL;
+ }
+#endif
+
+ memset(prof_buffer, 0, prof_len * sizeof(*prof_buffer));
+ return count;
+}
+
+static struct file_operations proc_profile_operations = {
+ NULL, /* lseek */
+ read_profile,
+ write_profile,
+};
+
+static struct inode_operations proc_profile_inode_operations = {
+ &proc_profile_operations,
+};
+
+static struct proc_dir_entry proc_root_kmsg = {
+ 0, 4, "kmsg",
+ S_IFREG | S_IRUSR, 1, 0, 0,
+ 0, &proc_kmsg_inode_operations
+};
+struct proc_dir_entry proc_root_kcore = {
+ 0, 5, "kcore",
+ S_IFREG | S_IRUSR, 1, 0, 0,
+ 0, &proc_kcore_inode_operations
+};
+static struct proc_dir_entry proc_root_profile = {
+ 0, 7, "profile",
+ S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
+ 0, &proc_profile_inode_operations
+};
+
+void proc_misc_init(void)
+{
+ static struct {
+ char *name;
+ int (*read_proc)(char*,char**,off_t,int,int*,void*);
+ } *p, simple_ones[] = {
+ {"loadavg", loadavg_read_proc},
+ {"uptime", uptime_read_proc},
+ {"meminfo", meminfo_read_proc},
+ {"version", version_read_proc},
+ {"cpuinfo", cpuinfo_read_proc},
+#ifdef CONFIG_PROC_HARDWARE
+ {"hardware", hardware_read_proc},
+#endif
+#ifdef CONFIG_STRAM_PROC
+ {"stram", stram_read_proc},
+#endif
+#ifdef CONFIG_DEBUG_MALLOC
+ {"malloc", malloc_read_proc},
+#endif
+#ifdef CONFIG_MODULES
+ {"modules", modules_read_proc},
+ {"ksyms", ksyms_read_proc},
+#endif
+ {"stat", kstat_read_proc},
+ {"devices", devices_read_proc},
+ {"partitions", partitions_read_proc},
+ {"interrupts", interrupts_read_proc},
+ {"filesystems", filesystems_read_proc},
+ {"dma", dma_read_proc},
+ {"ioports", ioports_read_proc},
+ {"cmdline", cmdline_read_proc},
+#ifdef CONFIG_RTC
+ {"rtc", rtc_read_proc},
+#endif
+#ifdef CONFIG_SGI_DS1286
+ {"rtc", ds1286_read_proc},
+#endif
+ {"locks", locks_read_proc},
+ {"mounts", mounts_read_proc},
+ {"swaps", swaps_read_proc},
+ {"slabinfo", slabinfo_read_proc},
+ {"iomem", memory_read_proc},
+ {"execdomains", execdomains_read_proc},
+ {NULL,NULL}
+ };
+ for(p=simple_ones;p->name;p++)
+ create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL);
+
+ /* And now for trickier ones */
+ proc_register(&proc_root, &proc_root_kmsg);
+ proc_register(&proc_root, &proc_root_kcore);
+ proc_root_kcore.size = (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE;
+ if (prof_shift) {
+ proc_register(&proc_root, &proc_root_profile);
+ proc_root_profile.size = (1+prof_len) * sizeof(unsigned int);
+ }
+}
diff --git a/fs/proc/procfs_syms.c b/fs/proc/procfs_syms.c
index c6d0032c5..fa2ee362e 100644
--- a/fs/proc/procfs_syms.c
+++ b/fs/proc/procfs_syms.c
@@ -3,15 +3,7 @@
#include <linux/fs.h>
#include <linux/proc_fs.h>
-/*
- * This is all required so that if we load all of scsi as a module,
- * that the scsi code will be able to talk to the /proc/scsi handling
- * in the procfs.
- */
-extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
- off_t offset, int length, int inout);
-extern struct inode_operations proc_scsi_inode_operations;
-extern struct proc_dir_entry proc_sys_root;
+extern struct proc_dir_entry *proc_sys_root;
#ifdef CONFIG_SYSCTL
EXPORT_SYMBOL(proc_sys_root);
@@ -24,18 +16,9 @@ EXPORT_SYMBOL(proc_root);
EXPORT_SYMBOL(proc_root_fs);
EXPORT_SYMBOL(proc_get_inode);
EXPORT_SYMBOL(proc_dir_inode_operations);
-EXPORT_SYMBOL(proc_net_inode_operations);
EXPORT_SYMBOL(proc_net);
EXPORT_SYMBOL(proc_bus);
-/*
- * This is required so that if we load scsi later, that the
- * scsi code can attach to /proc/scsi in the correct manner.
- */
-EXPORT_SYMBOL(proc_scsi);
-EXPORT_SYMBOL(proc_scsi_inode_operations);
-EXPORT_SYMBOL(dispatch_scsi_info_ptr);
-
#if defined(CONFIG_SUN_OPENPROMFS_MODULE)
EXPORT_SYMBOL(proc_openprom_register);
EXPORT_SYMBOL(proc_openprom_deregister);
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 84478312c..b87b0fb4f 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -22,11 +22,6 @@
#include <linux/zorro.h>
#endif
-/*
- * Offset of the first process in the /proc root directory..
- */
-#define FIRST_PROCESS_ENTRY 256
-
static int proc_root_readdir(struct file *, void *, filldir_t);
static struct dentry *proc_root_lookup(struct inode *,struct dentry *);
static int proc_unlink(struct inode *, struct dentry *);
@@ -37,22 +32,12 @@ static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
* These are the generic /proc directory operations. They
* use the in-memory "struct proc_dir_entry" tree to parse
* the /proc directory.
- *
- * NOTE! The /proc/scsi directory currently does not correctly
- * build up the proc_dir_entry tree, and will show up empty.
*/
static struct file_operations proc_dir_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
NULL, /* write - bad */
proc_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 */
};
/*
@@ -62,23 +47,6 @@ struct inode_operations proc_dir_inode_operations = {
&proc_dir_operations, /* default net directory file-ops */
NULL, /* create */
proc_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, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
};
/*
@@ -90,21 +58,6 @@ struct inode_operations proc_dyna_dir_inode_operations = {
proc_lookup, /* lookup */
NULL, /* link */
proc_unlink, /* unlink(struct inode *, struct dentry *) */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
};
/*
@@ -117,13 +70,6 @@ static struct file_operations proc_root_operations = {
NULL, /* read - bad */
NULL, /* write - bad */
proc_root_readdir, /* readdir */
- NULL, /* poll - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* no fsync */
};
/*
@@ -133,23 +79,6 @@ static struct inode_operations proc_root_inode_operations = {
&proc_root_operations, /* default base directory file-ops */
NULL, /* create */
proc_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, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
};
/*
@@ -164,27 +93,14 @@ struct proc_dir_entry proc_root = {
&proc_root, NULL
};
-struct proc_dir_entry *proc_net, *proc_scsi, *proc_bus, *proc_sysvipc;
+struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver;
#ifdef CONFIG_MCA
-struct proc_dir_entry proc_mca = {
- PROC_MCA, 3, "mca",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL, &proc_root, NULL
-};
+struct proc_dir_entry *proc_mca;
#endif
#ifdef CONFIG_SYSCTL
-struct proc_dir_entry proc_sys_root = {
- PROC_SYS, 3, "sys", /* inode, name */
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, /* mode, nlink, uid, gid */
- 0, &proc_dir_inode_operations, /* size, ops */
- NULL, NULL, /* get_info, fill_inode */
- NULL, /* next */
- NULL, NULL /* parent, subdir */
-};
+struct proc_dir_entry *proc_sys_root;
#endif
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
@@ -280,36 +196,12 @@ static struct file_operations proc_openprom_operations = {
NULL, /* read - bad */
NULL, /* write - bad */
OPENPROM_DEFREADDIR, /* 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 */
};
struct inode_operations proc_openprom_inode_operations = {
&proc_openprom_operations,/* default net directory file-ops */
NULL, /* create */
OPENPROM_DEFLOOKUP, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
};
struct proc_dir_entry proc_openprom = {
@@ -333,6 +225,73 @@ static int make_inode_number(void)
return PROC_DYNAMIC_FIRST + i;
}
+int proc_readlink(struct dentry * dentry, char * buffer, int buflen)
+{
+ struct inode *inode = dentry->d_inode;
+ struct proc_dir_entry * de;
+ char *page;
+ int len = 0;
+
+ de = (struct proc_dir_entry *) inode->u.generic_ip;
+ if (!de)
+ return -ENOENT;
+ if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+
+ if (de->readlink_proc)
+ len = de->readlink_proc(de, page);
+
+ if (len > buflen)
+ len = buflen;
+
+ copy_to_user(buffer, page, len);
+ free_page((unsigned long) page);
+ return len;
+}
+
+struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base, unsigned int follow)
+{
+ struct inode *inode = dentry->d_inode;
+ struct proc_dir_entry * de;
+ char *page;
+ struct dentry *d;
+ int len = 0;
+
+ de = (struct proc_dir_entry *) inode->u.generic_ip;
+ if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+ return NULL;
+
+ if (de->readlink_proc)
+ len = de->readlink_proc(de, page);
+
+ d = lookup_dentry(page, base, follow);
+ free_page((unsigned long) page);
+ return d;
+}
+
+static struct inode_operations proc_link_inode_operations = {
+ NULL, /* no file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ proc_readlink, /* readlink */
+ proc_follow_link, /* follow_link */
+ NULL, /* get_block */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* flushpage */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
+};
+
int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
{
int i;
@@ -445,50 +404,6 @@ static struct dentry * proc_self_follow_link(struct dentry *dentry,
return lookup_dentry(tmp, base, follow);
}
-int proc_readlink(struct dentry * dentry, char * buffer, int buflen)
-{
- struct inode *inode = dentry->d_inode;
- struct proc_dir_entry * de;
- char *page;
- int len = 0;
-
- de = (struct proc_dir_entry *) inode->u.generic_ip;
- if (!de)
- return -ENOENT;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
-
- if (de->readlink_proc)
- len = de->readlink_proc(de, page);
-
- if (len > buflen)
- len = buflen;
-
- copy_to_user(buffer, page, len);
- free_page((unsigned long) page);
- return len;
-}
-
-struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base, unsigned int follow)
-{
- struct inode *inode = dentry->d_inode;
- struct proc_dir_entry * de;
- char *page;
- struct dentry *d;
- int len = 0;
-
- de = (struct proc_dir_entry *) inode->u.generic_ip;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
- return NULL;
-
- if (de->readlink_proc)
- len = de->readlink_proc(de, page);
-
- d = lookup_dentry(page, base, follow);
- free_page((unsigned long) page);
- return d;
-}
-
static struct inode_operations proc_self_inode_operations = {
NULL, /* no file-ops */
NULL, /* create */
@@ -512,286 +427,41 @@ static struct inode_operations proc_self_inode_operations = {
NULL /* revalidate */
};
-static struct inode_operations proc_link_inode_operations = {
- NULL, /* no file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- proc_readlink, /* readlink */
- proc_follow_link, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-static struct proc_dir_entry proc_root_loadavg = {
- PROC_LOADAVG, 7, "loadavg",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_uptime = {
- PROC_UPTIME, 6, "uptime",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_meminfo = {
- PROC_MEMINFO, 7, "meminfo",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_kmsg = {
- PROC_KMSG, 4, "kmsg",
- S_IFREG | S_IRUSR, 1, 0, 0,
- 0, &proc_kmsg_inode_operations
-};
-static struct proc_dir_entry proc_root_version = {
- PROC_VERSION, 7, "version",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_cpuinfo = {
- PROC_CPUINFO, 7, "cpuinfo",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#if defined (CONFIG_PROC_HARDWARE)
-static struct proc_dir_entry proc_root_hardware = {
- PROC_HARDWARE, 8, "hardware",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
-#ifdef CONFIG_STRAM_PROC
-static struct proc_dir_entry proc_root_stram = {
- PROC_STRAM, 5, "stram",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
static struct proc_dir_entry proc_root_self = {
- PROC_SELF, 4, "self",
+ 0, 4, "self",
S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
64, &proc_self_inode_operations,
};
-#ifdef CONFIG_DEBUG_MALLOC
-static struct proc_dir_entry proc_root_malloc = {
- PROC_MALLOC, 6, "malloc",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
-static struct proc_dir_entry proc_root_kcore = {
- PROC_KCORE, 5, "kcore",
- S_IFREG | S_IRUSR, 1, 0, 0,
- 0, &proc_kcore_inode_operations
-};
-#ifdef CONFIG_MODULES
-static struct proc_dir_entry proc_root_modules = {
- PROC_MODULES, 7, "modules",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_ksyms = {
- PROC_KSYMS, 5, "ksyms",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
-static struct proc_dir_entry proc_root_stat = {
- PROC_STAT, 4, "stat",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_devices = {
- PROC_DEVICES, 7, "devices",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_partitions = {
- PROC_PARTITIONS, 10, "partitions",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_interrupts = {
- PROC_INTERRUPTS, 10,"interrupts",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_filesystems = {
- PROC_FILESYSTEMS, 11,"filesystems",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-struct proc_dir_entry proc_root_fs = {
- PROC_FS, 2, "fs",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL,
- NULL, NULL
-};
-struct proc_dir_entry proc_root_driver = {
- PROC_DRIVER, 6, "driver",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL,
- NULL, NULL
-};
-static struct proc_dir_entry proc_root_dma = {
- PROC_DMA, 3, "dma",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_ioports = {
- PROC_IOPORTS, 7, "ioports",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_iomem = {
- PROC_MEMORY, 5, "iomem",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_cmdline = {
- PROC_CMDLINE, 7, "cmdline",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#ifdef CONFIG_RTC
-static struct proc_dir_entry proc_root_rtc = {
- PROC_RTC, 3, "rtc",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
-#ifdef CONFIG_SGI_DS1286
-static struct proc_dir_entry proc_root_ds1286 = {
- PROC_RTC, 3, "rtc",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-#endif
-static struct proc_dir_entry proc_root_locks = {
- PROC_LOCKS, 5, "locks",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_mounts = {
- PROC_MTAB, 6, "mounts",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_swaps = {
- PROC_SWAP, 5, "swaps",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
-static struct proc_dir_entry proc_root_profile = {
- PROC_PROFILE, 7, "profile",
- S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0,
- 0, &proc_profile_inode_operations
-};
-static struct proc_dir_entry proc_root_slab = {
- PROC_SLABINFO, 8, "slabinfo",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_array_inode_operations
-};
#ifdef __powerpc__
static struct proc_dir_entry proc_root_ppc_htab = {
- PROC_PPC_HTAB, 8, "ppc_htab",
+ 0, 8, "ppc_htab",
S_IFREG | S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, 1, 0, 0,
0, &proc_ppc_htab_inode_operations,
- NULL, NULL, /* get_info, fill_inode */
- NULL, /* next */
- NULL, NULL /* parent, subdir */
};
#endif
void __init proc_root_init(void)
{
- proc_base_init();
- proc_register(&proc_root, &proc_root_loadavg);
- proc_register(&proc_root, &proc_root_uptime);
- proc_register(&proc_root, &proc_root_meminfo);
- proc_register(&proc_root, &proc_root_kmsg);
- proc_register(&proc_root, &proc_root_version);
- proc_register(&proc_root, &proc_root_cpuinfo);
+ proc_misc_init();
proc_register(&proc_root, &proc_root_self);
proc_net = create_proc_entry("net", S_IFDIR, 0);
- proc_scsi = create_proc_entry("scsi", S_IFDIR, 0);
#ifdef CONFIG_SYSVIPC
- proc_sysvipc = create_proc_entry("sysvipc", S_IFDIR, 0);
+ create_proc_entry("sysvipc", S_IFDIR, 0);
#endif
#ifdef CONFIG_SYSCTL
- proc_register(&proc_root, &proc_sys_root);
+ proc_sys_root = create_proc_entry("sys", S_IFDIR, 0);
#endif
#ifdef CONFIG_MCA
- proc_register(&proc_root, &proc_mca);
-#endif
-
-#ifdef CONFIG_DEBUG_MALLOC
- proc_register(&proc_root, &proc_root_malloc);
-#endif
- proc_register(&proc_root, &proc_root_kcore);
- proc_root_kcore.size = (MAP_NR(high_memory) << PAGE_SHIFT) + PAGE_SIZE;
-
-#ifdef CONFIG_MODULES
- proc_register(&proc_root, &proc_root_modules);
- proc_register(&proc_root, &proc_root_ksyms);
-#endif
- proc_register(&proc_root, &proc_root_stat);
- proc_register(&proc_root, &proc_root_devices);
- proc_register(&proc_root, &proc_root_driver);
- proc_register(&proc_root, &proc_root_partitions);
- proc_register(&proc_root, &proc_root_interrupts);
- proc_register(&proc_root, &proc_root_filesystems);
- proc_register(&proc_root, &proc_root_fs);
- proc_register(&proc_root, &proc_root_dma);
- proc_register(&proc_root, &proc_root_ioports);
- proc_register(&proc_root, &proc_root_iomem);
- proc_register(&proc_root, &proc_root_cmdline);
-#ifdef CONFIG_RTC
- proc_register(&proc_root, &proc_root_rtc);
-#endif
-#ifdef CONFIG_SGI_DS1286
- proc_register(&proc_root, &proc_root_ds1286);
+ proc_mca = create_proc_entry("mca", S_IFDIR, 0);
#endif
- proc_register(&proc_root, &proc_root_locks);
-
- proc_register(&proc_root, &proc_root_mounts);
- proc_register(&proc_root, &proc_root_swaps);
-
+ proc_root_fs = create_proc_entry("fs", S_IFDIR, 0);
+ proc_root_driver = create_proc_entry("driver", S_IFDIR, 0);
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
#ifdef CONFIG_SUN_OPENPROMFS
openpromfs_init ();
#endif
proc_register(&proc_root, &proc_openprom);
#endif
-#ifdef CONFIG_PROC_HARDWARE
- proc_register(&proc_root, &proc_root_hardware);
-#endif
-#ifdef CONFIG_STRAM_PROC
- proc_register(&proc_root, &proc_root_stram);
-#endif
- proc_register(&proc_root, &proc_root_slab);
-
- if (prof_shift) {
- proc_register(&proc_root, &proc_root_profile);
- proc_root_profile.size = (1+prof_len) * sizeof(unsigned int);
- }
-
proc_tty_init();
#ifdef __powerpc__
proc_register(&proc_root, &proc_root_ppc_htab);
@@ -799,7 +469,6 @@ void __init proc_root_init(void)
#ifdef CONFIG_PROC_DEVICETREE
proc_device_tree_init();
#endif
-
proc_bus = create_proc_entry("bus", S_IFDIR, 0);
}
@@ -843,7 +512,7 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry)
if (de->namelen != dentry->d_name.len)
continue;
if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
- int ino = de->low_ino | (dir->i_ino & ~(0xffff));
+ int ino = de->low_ino;
error = -EINVAL;
inode = proc_get_inode(dir->i_sb, ino, de);
break;
@@ -861,11 +530,7 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry)
static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry)
{
- unsigned int pid, c;
struct task_struct *p;
- const char *name;
- struct inode *inode;
- int len;
if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */
extern unsigned long total_forks;
@@ -896,40 +561,7 @@ static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentr
if (!proc_lookup(dir, dentry))
return NULL;
- pid = 0;
- name = dentry->d_name.name;
- len = dentry->d_name.len;
- while (len-- > 0) {
- c = *name - '0';
- name++;
- if (c > 9) {
- pid = 0;
- break;
- }
- pid *= 10;
- pid += c;
- if (!pid)
- break;
- if (pid & 0xffff0000) {
- pid = 0;
- break;
- }
- }
- read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
- read_unlock(&tasklist_lock);
- inode = NULL;
- if (pid && p) {
- unsigned long ino = (pid << 16) + PROC_PID_INO;
- inode = proc_get_inode(dir->i_sb, ino, &proc_pid);
- if (!inode)
- return ERR_PTR(-EINVAL);
- inode->i_flags|=S_IMMUTABLE;
- }
-
- dentry->d_op = &proc_dentry_operations;
- d_add(dentry, inode);
- return NULL;
+ return proc_pid_lookup(dir, dentry);
}
/*
@@ -968,7 +600,6 @@ int proc_readdir(struct file * filp,
filp->f_pos++;
/* fall through */
default:
- ino &= ~0xffff;
de = de->subdir;
i -= 2;
for (;;) {
@@ -981,7 +612,7 @@ int proc_readdir(struct file * filp,
}
do {
- if (filldir(dirent, de->name, de->namelen, filp->f_pos, ino | de->low_ino) < 0)
+ if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino) < 0)
return 0;
filp->f_pos++;
de = de->next;
@@ -990,69 +621,19 @@ int proc_readdir(struct file * filp,
return 1;
}
-#define PROC_NUMBUF 10
-#define PROC_MAXPIDS 20
-
-/*
- * Get a few pid's to return for filldir - we need to hold the
- * tasklist lock while doing this, and we must release it before
- * we actually do the filldir itself, so we use a temp buffer..
- */
-static int get_pid_list(int index, unsigned int *pids)
-{
- struct task_struct *p;
- int nr_pids = 0;
-
- index -= FIRST_PROCESS_ENTRY;
- read_lock(&tasklist_lock);
- for_each_task(p) {
- int pid = p->pid;
- if (!pid)
- continue;
- if (--index >= 0)
- continue;
- pids[nr_pids] = pid;
- nr_pids++;
- if (nr_pids >= PROC_MAXPIDS)
- break;
- }
- read_unlock(&tasklist_lock);
- return nr_pids;
-}
-
static int proc_root_readdir(struct file * filp,
void * dirent, filldir_t filldir)
{
- unsigned int pid_array[PROC_MAXPIDS];
- char buf[PROC_NUMBUF];
unsigned int nr = filp->f_pos;
- unsigned int nr_pids, i;
if (nr < FIRST_PROCESS_ENTRY) {
int error = proc_readdir(filp, dirent, filldir);
if (error <= 0)
return error;
- filp->f_pos = nr = FIRST_PROCESS_ENTRY;
+ filp->f_pos = FIRST_PROCESS_ENTRY;
}
- nr_pids = get_pid_list(nr, pid_array);
-
- for (i = 0; i < nr_pids; i++) {
- int pid = pid_array[i];
- ino_t ino = (pid << 16) + PROC_PID_INO;
- unsigned long j = PROC_NUMBUF;
-
- do {
- j--;
- buf[j] = '0' + (pid % 10);
- pid /= 10;
- } while (pid);
-
- if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino) < 0)
- break;
- filp->f_pos++;
- }
- return 0;
+ return proc_pid_readdir(filp, dirent, filldir);
}
static int proc_unlink(struct inode *dir, struct dentry *dentry)
diff --git a/fs/proc/scsi.c b/fs/proc/scsi.c
deleted file mode 100644
index 679fa383f..000000000
--- a/fs/proc/scsi.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * linux/fs/proc/scsi.c
- * (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
- *
- * The original version was derived from linux/fs/proc/net.c,
- * which is Copyright (C) 1991, 1992 Linus Torvalds.
- * Much has been rewritten, but some of the code still remains.
- *
- * /proc/scsi directory handling functions
- *
- * last change: 95/07/04
- *
- * Initial version: March '95
- * 95/05/15 Added subdirectories for each driver and show every
- * registered HBA as a single file.
- * 95/05/30 Added rudimentary write support for parameter passing
- * 95/07/04 Fixed bugs in directory handling
- * 95/09/13 Update to support the new proc-dir tree
- *
- * TODO: Improve support to write to the driver files
- * Add some more comments
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-
-#include <asm/uaccess.h>
-
-/* forward references */
-static ssize_t proc_readscsi(struct file * file, char * buf,
- size_t count, loff_t *ppos);
-static ssize_t proc_writescsi(struct file * file, const char * buf,
- size_t count, loff_t *ppos);
-static long long proc_scsilseek(struct file *, long long, int);
-
-extern void build_proc_dir_hba_entries(uint);
-
-/* the *_get_info() functions are in the respective scsi driver code */
-int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
- off_t offset, int length, int inout) = 0;
-
-static struct file_operations proc_scsi_operations = {
- proc_scsilseek, /* lseek */
- proc_readscsi, /* read */
- proc_writescsi, /* write */
- proc_readdir, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-/*
- * proc directories can do almost nothing..
- */
-struct inode_operations proc_scsi_inode_operations = {
-&proc_scsi_operations, /* default scsi directory file-ops */
- NULL, /* create */
- proc_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, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-int get_not_present_info(char *buffer, char **start, off_t offset, int length)
-{
- int len, pos, begin;
-
- begin = 0;
- pos = len = sprintf(buffer,
- "No low-level scsi modules are currently present\n");
- if(pos < offset) {
- len = 0;
- begin = pos;
- }
-
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin);
- if(len > length)
- len = length;
-
- return(len);
-}
-
-#define PROC_BLOCK_SIZE (3*1024) /* 4K page size, but our output routines
- * use some slack for overruns
- */
-
-static ssize_t proc_readscsi(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- ssize_t length;
- ssize_t bytes = count;
- ssize_t copied = 0;
- ssize_t thistime;
- char * page;
- char * start;
-
- if (!(page = (char *) __get_free_page(GFP_KERNEL)))
- return(-ENOMEM);
-
- while (bytes > 0) {
- thistime = bytes;
- if(bytes > PROC_BLOCK_SIZE)
- thistime = PROC_BLOCK_SIZE;
-
- if(dispatch_scsi_info_ptr)
- length = dispatch_scsi_info_ptr(inode->i_ino, page, &start,
- *ppos, thistime, 0);
- else
- length = get_not_present_info(page, &start, *ppos, thistime);
- if(length < 0) {
- free_page((ulong) page);
- return(length);
- }
-
- /*
- * We have been given a non page aligned block of
- * the data we asked for + a bit. We have been given
- * the start pointer and we know the length..
- */
- if (length <= 0)
- break;
- /*
- * Copy the bytes
- */
- copy_to_user(buf + copied, start, length);
- *ppos += length; /* Move down the file */
- bytes -= length;
- copied += length;
-
- if(length < thistime)
- break; /* End of file */
-
- }
-
- free_page((ulong) page);
- return(copied);
-}
-
-
-static ssize_t proc_writescsi(struct file * file, const char * buf,
- size_t count, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- ssize_t ret = 0;
- char * page;
-
- if(count > PROC_BLOCK_SIZE) {
- return(-EOVERFLOW);
- }
-
- if(dispatch_scsi_info_ptr != NULL) {
- if (!(page = (char *) __get_free_page(GFP_KERNEL)))
- return(-ENOMEM);
- copy_from_user(page, buf, count);
- ret = dispatch_scsi_info_ptr(inode->i_ino, page, 0, 0, count, 1);
- } else
- return(-ENOPKG); /* Nothing here */
-
- free_page((ulong) page);
- return(ret);
-}
-
-
-static long long proc_scsilseek(struct file * file, long long offset, int orig)
-{
- switch (orig) {
- case 0:
- file->f_pos = offset;
- return(file->f_pos);
- case 1:
- file->f_pos += offset;
- return(file->f_pos);
- case 2:
- return(-EINVAL);
- default:
- return(-EINVAL);
- }
-}
-
-/*
- * Overrides for Emacs so that we almost follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff --git a/fs/proc/sysvipc.c b/fs/proc/sysvipc.c
deleted file mode 100644
index 7fff0ed03..000000000
--- a/fs/proc/sysvipc.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * linux/fs/proc/sysvipc.c
- *
- * Copyright (c) 1999 Dragos Acostachioaie
- *
- * This code is derived from linux/fs/proc/generic.c,
- * which is Copyright (C) 1991, 1992 Linus Torvalds.
- *
- * /proc/sysvipc directory handling functions
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-
-#include <asm/uaccess.h>
-
-#ifndef MIN
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
-/* 4K page size but our output routines use some slack for overruns */
-#define PROC_BLOCK_SIZE (3*1024)
-
-static ssize_t
-proc_sysvipc_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
-{
- struct inode * inode = file->f_dentry->d_inode;
- char *page;
- ssize_t retval=0;
- int eof=0;
- ssize_t n, count;
- char *start;
- struct proc_dir_entry * dp;
-
- dp = (struct proc_dir_entry *) inode->u.generic_ip;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
-
- while ((nbytes > 0) && !eof)
- {
- count = MIN(PROC_BLOCK_SIZE, nbytes);
-
- start = NULL;
- if (dp->get_info) {
- /*
- * Handle backwards compatibility with the old net
- * routines.
- *
- * XXX What gives with the file->f_flags & O_ACCMODE
- * test? Seems stupid to me....
- */
- n = dp->get_info(page, &start, *ppos, count,
- (file->f_flags & O_ACCMODE) == O_RDWR);
- if (n < count)
- eof = 1;
- } else if (dp->read_proc) {
- n = dp->read_proc(page, &start, *ppos,
- count, &eof, dp->data);
- } else
- break;
-
- if (!start) {
- /*
- * For proc files that are less than 4k
- */
- start = page + *ppos;
- n -= *ppos;
- if (n <= 0)
- break;
- if (n > count)
- n = count;
- }
- if (n == 0)
- break; /* End of file */
- if (n < 0) {
- if (retval == 0)
- retval = n;
- break;
- }
-
- /* This is a hack to allow mangling of file pos independent
- * of actual bytes read. Simply place the data at page,
- * return the bytes, and set `start' to the desired offset
- * as an unsigned int. - Paul.Russell@rustcorp.com.au
- */
- n -= copy_to_user(buf, start < page ? page : start, n);
- if (n == 0) {
- if (retval == 0)
- retval = -EFAULT;
- break;
- }
-
- *ppos += start < page ? (long)start : n; /* Move down the file */
- nbytes -= n;
- buf += n;
- retval += n;
- }
- free_page((unsigned long) page);
- return retval;
-}
-
-static struct file_operations proc_sysvipc_operations = {
- NULL, /* lseek */
- proc_sysvipc_read, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* poll */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* no special release code */
- NULL /* can't fsync */
-};
-
-/*
- * proc directories can do almost nothing..
- */
-struct inode_operations proc_sysvipc_inode_operations = {
- &proc_sysvipc_operations, /* default net file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
diff --git a/fs/read_write.c b/fs/read_write.c
index 81f6d1141..eb729a4fd 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -63,8 +63,12 @@ asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
!(inode = dentry->d_inode))
goto out_putf;
retval = -EINVAL;
- if (origin <= 2)
- retval = llseek(file, offset, origin);
+ if (origin <= 2) {
+ loff_t res = llseek(file, offset, origin);
+ retval = res;
+ if (res != (loff_t)retval)
+ retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */
+ }
out_putf:
fput(file);
bad:
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index 539b60da9..7cb561704 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -34,6 +34,21 @@
* exposed a problem in readdir
* 2.1.107 code-freeze spellchecker run
* Aug 1998 2.1.118+ VFS changes
+ * Sep 1998 2.1.122 another VFS change (follow_link)
+ * Apr 1999 2.2.7 no more EBADF checking in
+ * lookup/readdir, use ERR_PTR
+ * Jun 1999 2.3.6 d_alloc_root use changed
+ * 2.3.9 clean up usage of ENOENT/negative
+ * dentries in lookup
+ * clean up page flags setting
+ * (error, uptodate, locking) in
+ * in readpage
+ * use init_special_inode for
+ * fifos/sockets (and streamline) in
+ * read_inode, fix _ops table order
+ * Aug 1999 2.3.16 __initfunc() => __init change
+ * Oct 1999 2.3.24 page->owner hack obsoleted
+ * Nov 1999 2.3.27 2.3.25+ page->offset => index change
*/
/* todo:
@@ -404,7 +419,8 @@ romfs_readpage(struct file * file, struct page * page)
get_page(page);
buf = page_address(page);
- offset = page->offset;
+ /* 32 bit warning -- but not for us :) */
+ offset = page->index << PAGE_CACHE_SHIFT;
if (offset < inode->i_size) {
avail = inode->i_size-offset;
readlen = min(avail, PAGE_SIZE);
diff --git a/fs/smbfs/cache.c b/fs/smbfs/cache.c
index efb472d4b..17251b80b 100644
--- a/fs/smbfs/cache.c
+++ b/fs/smbfs/cache.c
@@ -48,30 +48,39 @@ get_cached_page(struct address_space *mapping, unsigned long offset, int new)
{
struct page * page;
struct page ** hash;
- unsigned long new_page;
+ struct page *cached_page = NULL;
again:
hash = page_hash(mapping, offset);
page = __find_lock_page(mapping, offset, hash);
if(!page && new) {
- /* not in cache, alloc a new page */
- new_page = page_cache_alloc();
- if (!new_page)
- return 0;
- clear_page(new_page); /* smb code assumes pages are zeroed */
- page = page_cache_entry(new_page);
- if (add_to_page_cache_unique(page, mapping, offset, hash)) {
+ /* not in cache, alloc a new page if we didn't do it yet */
+ if (!cached_page) {
+ cached_page = page_cache_alloc();
+ if (!cached_page)
+ return 0;
+ /* smb code assumes pages are zeroed */
+ clear_page(page_address(cached_page));
+ goto again;
+ }
+ page = cached_page;
+ if (page->buffers)
+ BUG();
+ printk(KERN_DEBUG "smbfs: get_cached_page\n");
+ if (add_to_page_cache_unique(page, mapping, offset, hash))
/* Hmm, a page has materialized in the
cache. Fine. Go back and get that page
- instead ... throwing away this one first. */
- put_cached_page((unsigned long) page);
+ instead... */
goto again;
- }
+ cached_page = NULL;
}
+ printk(KERN_DEBUG "smbfs: get_cached_page done\n");
+ if (cached_page)
+ page_cache_free(cached_page);
if(!page)
return 0;
if(!PageLocked(page))
- printk(KERN_ERR "smbfs/cache.c: page isn't locked! This could be fun ...\n");
+ BUG();
return page_address(page);
}
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index 1aa6b711e..7ef18302f 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -49,7 +49,7 @@ static int
smb_readpage_sync(struct dentry *dentry, struct page *page)
{
char *buffer = (char *) page_address(page);
- unsigned long offset = page->offset;
+ unsigned long offset = page->index << PAGE_CACHE_SHIFT;
int rsize = smb_get_rsize(server_from_dentry(dentry));
int count = PAGE_SIZE;
int result;
@@ -128,7 +128,7 @@ smb_writepage_sync(struct dentry *dentry, struct page *page,
int wsize = smb_get_wsize(server_from_dentry(dentry));
int result, written = 0;
- offset += page->offset;
+ offset += page->index << PAGE_CACHE_SHIFT;
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_writepage_sync: file %s/%s, count=%d@%ld, wsize=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, count, offset, wsize);
@@ -191,7 +191,7 @@ smb_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
pr_debug("SMBFS: smb_updatepage(%s/%s %d@%ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- count, page->offset+offset);
+ count, (page->index << PAGE_CACHE_SHIFT)+offset);
return smb_writepage_sync(dentry, page, offset, count);
}
diff --git a/fs/super.c b/fs/super.c
index 3b58d13cc..9c8459248 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1025,14 +1025,14 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type,
struct dentry * dentry = NULL;
struct inode * inode = NULL;
kdev_t dev;
- int retval = -EPERM;
+ int retval;
unsigned long flags = 0;
unsigned long page = 0;
struct file dummy; /* allows read-write or read-only flag */
- lock_kernel();
if (!capable(CAP_SYS_ADMIN))
- goto out;
+ return -EPERM;
+ lock_kernel();
if ((new_flags &
(MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) {
retval = copy_mount_options (data, &page);
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index e27ac8d83..2a1626bdd 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -324,7 +324,7 @@ static int empty_dir(struct inode * inode)
block = 0;
bh = NULL;
pos = offset = 2*SYSV_DIRSIZE;
- if (inode->i_size % SYSV_DIRSIZE)
+ if ((unsigned long)(inode->i_size) % SYSV_DIRSIZE)
goto bad_dir;
if (inode->i_size < pos)
goto bad_dir;
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index 3bcda123c..f5ab39437 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -402,7 +402,7 @@ search_back:
got_block:
newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) -
- (group_start << 3);
+ (sizeof(struct SpaceBitmapDesc) << 3);
tmp = udf_get_pblock(sb, newblock, partition, 0);
if (!udf_clear_bit(bit, bh->b_data))
@@ -412,16 +412,6 @@ got_block:
}
mark_buffer_dirty(bh, 1);
- if (!(bh = getblk(sb->s_dev, tmp, sb->s_blocksize)))
- {
- udf_debug("cannot get block %d\n", tmp);
- unlock_super(sb);
- return 0;
- }
- memset(bh->b_data, 0, sb->s_blocksize);
- mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh, 1);
- udf_release_data(bh);
if (UDF_SB_LVIDBH(sb))
{
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index 50762e5f4..000ef6481 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -180,7 +180,7 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
&bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
{
block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
- if (++offset < (elen >> dir->i_sb->s_blocksize_bits))
+ if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
{
if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
extoffset -= sizeof(short_ad);
@@ -207,8 +207,6 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
filp->f_pos = nf_pos;
fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &bloc, &extoffset, &offset, &bh);
- liu = le16_to_cpu(cfi.lengthOfImpUse);
- lfi = cfi.lengthFileIdent;
if (!fi)
{
@@ -219,6 +217,9 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
return 1;
}
+ liu = le16_to_cpu(cfi.lengthOfImpUse);
+ lfi = cfi.lengthFileIdent;
+
if (fibh.sbh == fibh.ebh)
nameptr = fi->fileIdent + liu;
else
diff --git a/fs/udf/directory.c b/fs/udf/directory.c
index bc2ced009..7ea1ac38e 100644
--- a/fs/udf/directory.c
+++ b/fs/udf/directory.c
@@ -112,7 +112,7 @@ udf_fileident_read(struct inode *dir, int *nf_pos,
(*offset) ++;
- if (*offset >= (elen >> dir->i_sb->s_blocksize_bits))
+ if ((*offset << dir->i_sb->s_blocksize_bits) >= elen)
*offset = 0;
else
*extoffset = lextoffset;
@@ -154,7 +154,7 @@ udf_fileident_read(struct inode *dir, int *nf_pos,
(*offset) ++;
- if (*offset >= (elen >> dir->i_sb->s_blocksize_bits))
+ if ((*offset << dir->i_sb->s_blocksize_bits) >= elen)
*offset = 0;
else
*extoffset = lextoffset;
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 282466841..0a9642b08 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -213,6 +213,8 @@ static ssize_t udf_file_write(struct file * file, const char * buf,
if ((bh = udf_expand_adinicb(inode, &i, 0, &err)))
udf_release_data(bh);
+ else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+ return err;
}
retval = generic_file_write(file, buf, count, ppos, block_write_partial_page);
@@ -294,7 +296,9 @@ static ssize_t udf_file_read_adinicb(struct file * filp, char * buf,
if (!copy_to_user(buf, bh->b_data + pos, left))
*loff += left;
else
- return -EFAULT;
+ left = -EFAULT;
+
+ udf_release_data(bh);
return left;
}
@@ -336,11 +340,11 @@ static ssize_t udf_file_read_adinicb(struct file * filp, char * buf,
int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
- int result=-1;
- int size;
+ int result = -1;
struct buffer_head *bh = NULL;
- struct FileEntry *fe;
Uint16 ident;
+ long_ad eaicb;
+ Uint8 *ea = NULL;
if ( permission(inode, MAY_READ) != 0 )
{
@@ -368,26 +372,42 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
/* ok, we need to read the inode */
bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
- if (!bh || ident != TID_FILE_ENTRY)
+ if (!bh || (ident != TID_FILE_ENTRY && ident != TID_EXTENDED_FILE_ENTRY))
{
- udf_debug("bread failed (ino=%ld) or ident (%d) != TID_FILE_ENTRY",
+ udf_debug("bread failed (ino=%ld) or ident (%d) != TID_(EXTENDED_)FILE_ENTRY",
inode->i_ino, ident);
return -EFAULT;
}
- fe = (struct FileEntry *)bh->b_data;
- size = le32_to_cpu(fe->lengthExtendedAttr);
+ if (UDF_I_EXTENDED_FE(inode) == 0)
+ {
+ struct FileEntry *fe;
+
+ fe = (struct FileEntry *)bh->b_data;
+ eaicb = fe->extendedAttrICB;
+ if (UDF_I_LENEATTR(inode))
+ ea = fe->extendedAttr;
+ }
+ else
+ {
+ struct ExtendedFileEntry *efe;
+
+ efe = (struct ExtendedFileEntry *)bh->b_data;
+ eaicb = efe->extendedAttrICB;
+ if (UDF_I_LENEATTR(inode))
+ ea = efe->extendedAttr;
+ }
switch (cmd)
{
case UDF_GETEASIZE:
if ( (result = verify_area(VERIFY_WRITE, (char *)arg, 4)) == 0)
- result= put_user(size, (int *)arg);
+ result = put_user(UDF_I_LENEATTR(inode), (int *)arg);
break;
case UDF_GETEABLOCK:
- if ( (result = verify_area(VERIFY_WRITE, (char *)arg, size)) == 0)
- result= copy_to_user((char *)arg, fe->extendedAttr, size);
+ if ( (result = verify_area(VERIFY_WRITE, (char *)arg, UDF_I_LENEATTR(inode))) == 0)
+ result = copy_to_user((char *)arg, ea, UDF_I_LENEATTR(inode));
break;
default:
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 3cb450036..71083a7bd 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -106,18 +106,48 @@ void udf_delete_inode(struct inode * inode)
void udf_discard_prealloc(struct inode * inode)
{
#ifdef UDF_PREALLOCATE
-#if 0
- unsigned short total;
- lb_addr loc = UDF_I_LOCATION(inode);
+ lb_addr bloc, eloc;
+ Uint32 extoffset, elen, nelen, offset, adsize = 0;
+ struct buffer_head *bh = NULL;
- if (UDF_I_PREALLOC_COUNT(inode))
+ if ((inode->i_size > 0) &&
+ (inode_bmap(inode, (inode->i_size-1) >> inode->i_sb->s_blocksize_bits,
+ &bloc, &extoffset, &eloc, &elen, &offset, &bh) ==
+ EXTENT_RECORDED_ALLOCATED))
{
- total = UDF_I_PREALLOC_COUNT(inode);
- UDF_I_PREALLOC_COUNT(inode) = 0;
- loc.logicalBlockNum = UDF_I_PREALLOC_BLOCK(inode);
- udf_free_blocks(inode, loc, 0, total);
+ if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+ adsize = sizeof(short_ad);
+ else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+ adsize = sizeof(long_ad);
+ else
+ {
+ udf_release_data(bh);
+ return;
+ }
+
+ nelen = (EXTENT_RECORDED_ALLOCATED << 30) |
+ ((((elen - 1) & ~(inode->i_sb->s_blocksize - 1)) |
+ ((inode->i_size - 1) & (inode->i_sb->s_blocksize - 1))) + 1);
+
+ if (nelen != ((EXTENT_RECORDED_ALLOCATED << 30) | elen))
+ {
+ extoffset -= adsize;
+ udf_write_aext(inode, bloc, &extoffset, eloc, nelen, &bh, 1);
+ }
+
+ if (udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 0) ==
+ EXTENT_NOT_RECORDED_ALLOCATED)
+ {
+ udf_free_blocks(inode, eloc, 0, elen >> inode->i_sb->s_blocksize_bits);
+ memset(&eloc, 0x00, sizeof(lb_addr));
+ udf_write_aext(inode, bloc, &extoffset, eloc, 0, &bh, 1);
+ UDF_I_LENALLOC(inode) -= adsize;
+ udf_write_inode(inode);
+ }
+ udf_release_data(bh);
}
-#endif
+ else if (bh)
+ udf_release_data(bh);
#endif
}
@@ -144,6 +174,9 @@ struct buffer_head * udf_expand_adinicb(struct inode *inode, int *block, int isd
{
UDF_I_EXT0OFFS(inode) = 0;
UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG;
+ mark_inode_dirty(inode);
+ if (inode->i_op == &udf_file_inode_operations_adinicb)
+ inode->i_op = &udf_file_inode_operations;
return NULL;
}
@@ -208,6 +241,7 @@ struct buffer_head * udf_expand_adinicb(struct inode *inode, int *block, int isd
memset(sbh->b_data + udf_file_entry_alloc_offset(inode),
0, UDF_I_LENALLOC(inode));
+ memset(&newad, 0x00, sizeof(long_ad));
newad.extLength = UDF_I_EXT0LEN(inode) = inode->i_size;
newad.extLocation.logicalBlockNum = *block;
newad.extLocation.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
@@ -248,7 +282,7 @@ struct buffer_head * udf_getblk(struct inode * inode, long block,
bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
if (buffer_new(&dummy))
{
- memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+ memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
mark_buffer_uptodate(bh, 1);
mark_buffer_dirty(bh, 1);
}
@@ -340,6 +374,7 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
if (pbh != cbh)
{
udf_release_data(pbh);
+ pbh = cbh;
atomic_inc(&cbh->b_count);
pbloc = cbloc;
}
@@ -462,7 +497,6 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
UDF_I_LOCATION(inode).partitionReferenceNum, goal, err)))
{
udf_release_data(pbh);
- udf_release_data(cbh);
*err = -ENOSPC;
return NULL;
}
@@ -488,7 +522,7 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
udf_release_data(pbh);
- if (c == 0 || c == 1)
+ if (pextoffset == udf_file_entry_alloc_offset(inode))
{
UDF_I_EXT0LEN(inode) = laarr[0].extLength;
UDF_I_EXT0LOC(inode) = laarr[0].extLocation;
@@ -889,7 +923,8 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
{
struct FileEntry *fe;
struct ExtendedFileEntry *efe;
- time_t convtime;
+ time_t convtime;
+ long convtime_usec;
int offset, alen;
fe = (struct FileEntry *)bh->b_data;
@@ -940,21 +975,33 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
(inode->i_sb->s_blocksize_bits - 9);
- if ( udf_stamp_to_time(&convtime, lets_to_cpu(fe->modificationTime)) )
+ if ( udf_stamp_to_time(&convtime, &convtime_usec,
+ lets_to_cpu(fe->modificationTime)) )
{
inode->i_mtime = convtime;
+ UDF_I_UMTIME(inode) = convtime_usec;
inode->i_ctime = convtime;
+ UDF_I_UCTIME(inode) = convtime_usec;
}
else
{
inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb);
+ UDF_I_UMTIME(inode) = 0;
inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb);
+ UDF_I_UCTIME(inode) = 0;
}
- if ( udf_stamp_to_time(&convtime, lets_to_cpu(fe->accessTime)) )
+ if ( udf_stamp_to_time(&convtime, &convtime_usec,
+ lets_to_cpu(fe->accessTime)) )
+ {
inode->i_atime = convtime;
+ UDF_I_UATIME(inode) = convtime_usec;
+ }
else
+ {
inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb);
+ UDF_I_UATIME(inode) = convtime_usec;
+ }
UDF_I_UNIQUE(inode) = le64_to_cpu(fe->uniqueID);
UDF_I_LENEATTR(inode) = le32_to_cpu(fe->lengthExtendedAttr);
@@ -967,20 +1014,41 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
(inode->i_sb->s_blocksize_bits - 9);
- if ( udf_stamp_to_time(&convtime, lets_to_cpu(efe->modificationTime)) )
+ if ( udf_stamp_to_time(&convtime, &convtime_usec,
+ lets_to_cpu(efe->modificationTime)) )
+ {
inode->i_mtime = convtime;
+ UDF_I_UMTIME(inode) = convtime_usec;
+ }
else
+ {
inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb);
+ UDF_I_UMTIME(inode) = 0;
+ }
- if ( udf_stamp_to_time(&convtime, lets_to_cpu(efe->accessTime)) )
+ if ( udf_stamp_to_time(&convtime, &convtime_usec,
+ lets_to_cpu(efe->accessTime)) )
+ {
inode->i_atime = convtime;
+ UDF_I_UATIME(inode) = convtime_usec;
+ }
else
+ {
inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb);
+ UDF_I_UATIME(inode) = 0;
+ }
- if ( udf_stamp_to_time(&convtime, lets_to_cpu(efe->createTime)) )
+ if ( udf_stamp_to_time(&convtime, &convtime_usec,
+ lets_to_cpu(efe->createTime)) )
+ {
inode->i_ctime = convtime;
+ UDF_I_UCTIME(inode) = convtime_usec;
+ }
else
+ {
inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb);
+ UDF_I_UCTIME(inode) = 0;
+ }
UDF_I_UNIQUE(inode) = le64_to_cpu(efe->uniqueID);
UDF_I_LENEATTR(inode) = le32_to_cpu(efe->lengthExtendedAttr);
@@ -1274,8 +1342,8 @@ udf_update_inode(struct inode *inode, int do_sync)
efe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
efe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
efe->uniqueID = cpu_to_le64(UDF_I_UNIQUE(inode));
- efe->lengthExtendedAttr = cpu_to_le32(UDF_I_LENEATTR(inode));
- efe->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
+ efe->lengthExtendedAttr = cpu_to_le32(UDF_I_LENEATTR(inode));
+ efe->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
efe->descTag.tagIdent = le16_to_cpu(TID_EXTENDED_FILE_ENTRY);
crclen = sizeof(struct ExtendedFileEntry);
}
@@ -1764,6 +1832,8 @@ int udf_insert_aext(struct inode *inode, lb_addr bloc, int extoffset,
return -1;
}
}
+ else
+ atomic_inc(&bh->b_count);
while ((type = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1)
{
@@ -1773,6 +1843,7 @@ int udf_insert_aext(struct inode *inode, lb_addr bloc, int extoffset,
nelen = (type << 30) | oelen;
}
udf_add_aext(inode, &bloc, &extoffset, neloc, nelen, &bh, 1);
+ udf_release_data(bh);
return (nelen >> 30);
}
@@ -1879,12 +1950,12 @@ int inode_bmap(struct inode *inode, int block, lb_addr *bloc, Uint32 *extoffset,
if (block < 0)
{
printk(KERN_ERR "udf: inode_bmap: block < 0\n");
- return 0;
+ return -1;
}
if (!inode)
{
printk(KERN_ERR "udf: inode_bmap: NULL inode\n");
- return 0;
+ return -1;
}
b_off = block << inode->i_sb->s_blocksize_bits;
diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c
index 91ead3d39..635ab1b79 100644
--- a/fs/udf/lowlevel.c
+++ b/fs/udf/lowlevel.c
@@ -95,16 +95,17 @@ udf_get_last_block(kdev_t dev, int *flags)
int ret;
unsigned long lblock;
unsigned int hbsize = get_hardblocksize(dev);
+ unsigned int secsize = 512;
unsigned int mult = 0;
unsigned int div = 0;
if (!hbsize)
- hbsize = 512;
+ hbsize = blksize_size[MAJOR(dev)][MINOR(dev)];
- if (hbsize > blksize_size[MAJOR(dev)][MINOR(dev)])
- mult = hbsize / blksize_size[MAJOR(dev)][MINOR(dev)];
- else if (blksize_size[MAJOR(dev)][MINOR(dev)] > hbsize)
- div = blksize_size[MAJOR(dev)][MINOR(dev)] / hbsize;
+ if (secsize > hbsize)
+ mult = secsize / hbsize;
+ else if (hbsize > secsize)
+ div = hbsize / secsize;
if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
{
@@ -138,7 +139,7 @@ udf_get_last_block(kdev_t dev, int *flags)
}
set_fs(old_fs);
- if (!ret)
+ if (!ret && lblock)
return lblock - 1;
}
else
diff --git a/fs/udf/misc.c b/fs/udf/misc.c
index 2d7eb08f4..74b2c3965 100644
--- a/fs/udf/misc.c
+++ b/fs/udf/misc.c
@@ -24,11 +24,10 @@
* 04/19/99 blf partial support for reading/writing specific EA's
*/
+#include "udfdecl.h"
#if defined(__linux__) && defined(__KERNEL__)
-#include "udfdecl.h"
-
#include "udf_sb.h"
#include "udf_i.h"
@@ -38,7 +37,6 @@
#else
-#include "udfdecl.h"
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
@@ -66,28 +64,6 @@ udf64_high32(Uint64 indat)
return indat >> 32;
}
-/*
- * udf_stamp_to_time
- */
-time_t *
-udf_stamp_to_time(time_t *dest, timestamp src)
-{
- struct ktm tm;
-
- if ((!dest))
- return NULL;
-
- /* this is very rough. need to find source to mktime() */
- tm.tm_year=(src.year) - 1900;
- tm.tm_mon=(src.month);
- tm.tm_mday=(src.day);
- tm.tm_hour=src.hour;
- tm.tm_min=src.minute;
- tm.tm_sec=src.second;
- *dest = udf_converttime(&tm);
- return dest;
-}
-
uid_t udf_convert_uid(int uidin)
{
if ( uidin == -1 )
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 01b3979c9..712cf09fb 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -49,141 +49,95 @@ int udf_write_fi(struct FileIdentDesc *cfi, struct FileIdentDesc *sfi,
struct udf_fileident_bh *fibh,
Uint8 *impuse, Uint8 *fileident)
{
- struct FileIdentDesc *efi;
Uint16 crclen = fibh->eoffset - fibh->soffset - sizeof(tag);
Uint16 crc;
Uint8 checksum = 0;
int i;
- int offset, len;
- int padlen = fibh->eoffset - fibh->soffset - cfi->lengthOfImpUse - cfi->lengthFileIdent -
+ int offset;
+ Uint16 liu = le16_to_cpu(cfi->lengthOfImpUse);
+ Uint8 lfi = cfi->lengthFileIdent;
+ int padlen = fibh->eoffset - fibh->soffset - liu - lfi -
sizeof(struct FileIdentDesc);
- crc = udf_crc((Uint8 *)cfi + sizeof(tag), sizeof(struct FileIdentDesc) -
- sizeof(tag), 0);
- efi = (struct FileIdentDesc *)(fibh->ebh->b_data + fibh->soffset);
- if (fibh->sbh == fibh->ebh ||
- (!fileident &&
- (sizeof(struct FileIdentDesc) + (impuse ? cfi->lengthOfImpUse : 0))
- <= -fibh->soffset))
- {
- memcpy((Uint8 *)sfi, (Uint8 *)cfi, sizeof(struct FileIdentDesc));
-
- if (impuse)
- memcpy(sfi->impUse, impuse, cfi->lengthOfImpUse);
- if (fileident)
- memcpy(sfi->fileIdent + cfi->lengthOfImpUse, fileident,
- cfi->lengthFileIdent);
+ offset = fibh->soffset + sizeof(struct FileIdentDesc);
- /* Zero padding */
- memset(sfi->fileIdent + cfi->lengthOfImpUse + cfi->lengthFileIdent, 0,
- padlen);
-
- if (fibh->sbh == fibh->ebh)
- crc = udf_crc((Uint8 *)sfi + sizeof(tag), crclen, 0);
+ if (impuse)
+ {
+ if (offset + liu < 0)
+ memcpy((Uint8 *)sfi->impUse, impuse, liu);
+ else if (offset >= 0)
+ memcpy(fibh->ebh->b_data + offset, impuse, liu);
else
{
- crc = udf_crc((Uint8 *)sfi + sizeof(tag), crclen - fibh->eoffset, 0);
- crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
+ memcpy((Uint8 *)sfi->impUse, impuse, -offset);
+ memcpy(fibh->ebh->b_data, impuse - offset, liu + offset);
}
+ }
- sfi->descTag.descCRC = cpu_to_le32(crc);
- sfi->descTag.descCRCLength = cpu_to_le16(crclen);
-
- for (i=0; i<16; i++)
- if (i != 4)
- checksum += ((Uint8 *)&sfi->descTag)[i];
-
- sfi->descTag.tagChecksum = checksum;
+ offset += liu;
- mark_buffer_dirty(fibh->sbh, 1);
- }
- else
+ if (fileident)
{
- offset = -fibh->soffset;
- len = sizeof(struct FileIdentDesc);
-
- if (len <= offset)
- memcpy((Uint8 *)sfi, (Uint8 *)cfi, len);
+ if (offset + lfi < 0)
+ memcpy((Uint8 *)sfi->fileIdent + liu, fileident, lfi);
+ else if (offset >= 0)
+ memcpy(fibh->ebh->b_data + offset, fileident, lfi);
else
{
- memcpy((Uint8 *)sfi, (Uint8 *)cfi, offset);
- memcpy(fibh->ebh->b_data, (Uint8 *)cfi + offset, len - offset);
- }
-
- offset -= len;
- len = cfi->lengthOfImpUse;
-
- if (impuse)
- {
- if (offset <= 0)
- memcpy(efi->impUse, impuse, len);
- else if (sizeof(struct FileIdentDesc) + len <= -fibh->soffset)
- memcpy(sfi->impUse, impuse, len);
- else
- {
- memcpy(sfi->impUse, impuse, offset);
- memcpy(efi->impUse + offset, impuse + offset, len - offset);
- }
+ memcpy((Uint8 *)sfi->fileIdent + liu, fileident, -offset);
+ memcpy(fibh->ebh->b_data, fileident - offset, lfi + offset);
}
+ }
- offset -= len;
- len = cfi->lengthFileIdent;
+ offset += lfi;
- if (fileident)
- {
- if (offset <= 0)
- memcpy(efi->fileIdent + cfi->lengthOfImpUse, fileident, len);
- else
- {
- memcpy(sfi->fileIdent + cfi->lengthOfImpUse, fileident, offset);
- memcpy(efi->fileIdent + cfi->lengthOfImpUse + offset,
- fileident + offset, len - offset);
- }
- }
+ if (offset + padlen < 0)
+ memset((Uint8 *)sfi->padding + liu + lfi, 0x00, padlen);
+ else if (offset >= 0)
+ memset(fibh->ebh->b_data + offset, 0x00, padlen);
+ else
+ {
+ memset((Uint8 *)sfi->padding + liu + lfi, 0x00, -offset);
+ memset(fibh->ebh->b_data, 0x00, padlen + offset);
+ }
- /* Zero padding */
- memset(efi->fileIdent + cfi->lengthOfImpUse + cfi->lengthFileIdent, 0x00,
- padlen);
+ crc = udf_crc((Uint8 *)cfi + sizeof(tag), sizeof(struct FileIdentDesc) -
+ sizeof(tag), 0);
- if (sizeof(tag) < -fibh->soffset)
- {
- crc = udf_crc((Uint8 *)sfi + sizeof(tag), crclen - fibh->eoffset, 0);
- crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
- }
- else
- crc = udf_crc((Uint8 *)fibh->ebh->b_data + fibh->eoffset - crclen, crclen, 0);
+ if (fibh->sbh == fibh->ebh)
+ crc = udf_crc((Uint8 *)sfi->impUse,
+ crclen + sizeof(tag) - sizeof(struct FileIdentDesc), crc);
+ else if (sizeof(struct FileIdentDesc) >= -fibh->soffset)
+ crc = udf_crc(fibh->ebh->b_data + sizeof(struct FileIdentDesc) + fibh->soffset,
+ crclen + sizeof(tag) - sizeof(struct FileIdentDesc), crc);
+ else
+ {
+ crc = udf_crc((Uint8 *)sfi->impUse,
+ -fibh->soffset - sizeof(struct FileIdentDesc), crc);
+ crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
+ }
- if (&(efi->descTag.descCRC) < (Uint16 *)fibh->ebh->b_data)
- {
- sfi->descTag.descCRC = cpu_to_le16(crc);
- sfi->descTag.descCRCLength = cpu_to_le16(crclen);
- }
- else
- {
- efi->descTag.descCRC = cpu_to_le16(crc);
- efi->descTag.descCRCLength = cpu_to_le16(crclen);
- }
+ cfi->descTag.descCRC = cpu_to_le32(crc);
+ cfi->descTag.descCRCLength = cpu_to_le16(crclen);
- for (i=0; i<16; i++)
- {
- if (i != 4)
- {
- if (&(((Uint8 *)&efi->descTag)[i]) < (Uint8 *)fibh->ebh->b_data)
- checksum += ((Uint8 *)&sfi->descTag)[i];
- else
- checksum += ((Uint8 *)&efi->descTag)[i];
- }
- }
+ for (i=0; i<16; i++)
+ if (i != 4)
+ checksum += ((Uint8 *)&cfi->descTag)[i];
- if (&(cfi->descTag.tagChecksum) < (Uint8 *)fibh->ebh->b_data)
- sfi->descTag.tagChecksum = checksum;
- else
- efi->descTag.tagChecksum = checksum;
+ cfi->descTag.tagChecksum = checksum;
+ if (sizeof(struct FileIdentDesc) <= -fibh->soffset)
+ memcpy((Uint8 *)sfi, (Uint8 *)cfi, sizeof(struct FileIdentDesc));
+ else
+ {
+ memcpy((Uint8 *)sfi, (Uint8 *)cfi, -fibh->soffset);
+ memcpy(fibh->ebh->b_data, (Uint8 *)cfi - fibh->soffset,
+ sizeof(struct FileIdentDesc) + fibh->soffset);
+ }
- mark_buffer_dirty(fibh->sbh, 1);
+ if (fibh->sbh != fibh->ebh)
mark_buffer_dirty(fibh->ebh, 1);
- }
+ mark_buffer_dirty(fibh->sbh, 1);
return 0;
}
@@ -214,7 +168,7 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
&bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
{
block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
- if (++offset < (elen >> dir->i_sb->s_blocksize_bits))
+ if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
{
if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
extoffset -= sizeof(short_ad);
@@ -240,8 +194,6 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
while ( (f_pos < size) )
{
fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &offset, &bh);
- liu = le16_to_cpu(cfi->lengthOfImpUse);
- lfi = cfi->lengthFileIdent;
if (!fi)
{
@@ -252,6 +204,9 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
return NULL;
}
+ liu = le16_to_cpu(cfi->lengthOfImpUse);
+ lfi = cfi->lengthFileIdent;
+
if (fibh->sbh == fibh->ebh)
{
nameptr = fi->fileIdent + liu;
@@ -422,7 +377,7 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
&bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
{
block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
- if (++offset < (elen >> dir->i_sb->s_blocksize_bits))
+ if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
{
if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
extoffset -= sizeof(short_ad);
@@ -446,8 +401,6 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
while ( (f_pos < size) )
{
fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &offset, &bh);
- liu = le16_to_cpu(cfi->lengthOfImpUse);
- lfi = cfi->lengthFileIdent;
if (!fi)
{
@@ -458,6 +411,9 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
return NULL;
}
+ liu = le16_to_cpu(cfi->lengthOfImpUse);
+ lfi = cfi->lengthFileIdent;
+
if (fibh->sbh == fibh->ebh)
nameptr = fi->fileIdent + liu;
else
@@ -520,6 +476,8 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
fibh->soffset -= UDF_I_EXT0OFFS(dir);
fibh->eoffset -= UDF_I_EXT0OFFS(dir);
f_pos -= (UDF_I_EXT0OFFS(dir) >> 2);
+ if (fibh->sbh != fibh->ebh)
+ udf_release_data(fibh->ebh);
udf_release_data(fibh->sbh);
if (!(fibh->sbh = fibh->ebh = udf_expand_adinicb(dir, &block, 1, err)))
return NULL;
@@ -557,10 +515,12 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
}
else
{
- elen += nfidlen;
+ if (elen & (sb->s_blocksize - 1))
+ elen += nfidlen;
+ block = eloc.logicalBlockNum + ((elen - 1) >>
+ dir->i_sb->s_blocksize_bits);
elen = (EXTENT_RECORDED_ALLOCATED << 30) | elen;
udf_write_aext(dir, bloc, &lextoffset, eloc, elen, &bh, 1);
- block = eloc.logicalBlockNum + (elen >> dir->i_sb->s_blocksize_bits);
}
}
else
@@ -588,10 +548,16 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
return NULL;
}
else
- block = eloc.logicalBlockNum + (elen >> dir->i_sb->s_blocksize_bits);
+ {
+ elen = ((elen + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1));
+ block = eloc.logicalBlockNum + ((elen - 1) >>
+ dir->i_sb->s_blocksize_bits);
+ elen = (EXTENT_RECORDED_ALLOCATED << 30) | elen;
+ udf_write_aext(dir, bloc, &lextoffset, eloc, elen, &bh, 0);
+ }
*err = -ENOSPC;
- if (!(fibh->ebh = udf_getblk(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err)))
+ if (!(fibh->ebh = udf_bread(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err)))
{
udf_release_data(bh);
udf_release_data(fibh->sbh);
@@ -602,7 +568,8 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
if (udf_next_aext(dir, &bloc, &lextoffset, &eloc, &elen, &bh, 1) ==
EXTENT_RECORDED_ALLOCATED)
{
- block = eloc.logicalBlockNum + (elen >> dir->i_sb->s_blocksize_bits);
+ block = eloc.logicalBlockNum + ((elen - 1) >>
+ dir->i_sb->s_blocksize_bits);
}
else
block ++;
@@ -854,7 +821,7 @@ static int empty_dir(struct inode *dir)
&bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
{
block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
- if (++offset < (elen >> dir->i_sb->s_blocksize_bits))
+ if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
{
if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
extoffset -= sizeof(short_ad);
diff --git a/fs/udf/super.c b/fs/udf/super.c
index c6ff2c6e2..97a0843bb 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -768,18 +768,20 @@ udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
{
struct PrimaryVolDesc *pvoldesc;
time_t recording;
+ long recording_usec;
struct ustr instr;
struct ustr outstr;
pvoldesc = (struct PrimaryVolDesc *)bh->b_data;
- if ( udf_stamp_to_time(&recording, lets_to_cpu(pvoldesc->recordingDateAndTime)) )
+ if ( udf_stamp_to_time(&recording, &recording_usec,
+ lets_to_cpu(pvoldesc->recordingDateAndTime)) )
{
timestamp ts;
ts = lets_to_cpu(pvoldesc->recordingDateAndTime);
- udf_debug("recording time %ld, %u/%u/%u %u:%u (%x)\n",
- recording, ts.year, ts.month, ts.day, ts.hour, ts.minute,
- ts.typeAndTimezone);
+ udf_debug("recording time %ld/%ld, %04u/%02u/%02u %02u:%02u (%x)\n",
+ recording, recording_usec,
+ ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.typeAndTimezone);
UDF_SB_RECORDTIME(sb) = recording;
}
@@ -1182,7 +1184,7 @@ udf_load_partition(struct super_block *sb, lb_addr *fileset)
if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP15)
{
UDF_SB_TYPEVIRT(sb,i).s_start_offset = UDF_I_EXT0OFFS(UDF_SB_VAT(sb));
- UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size - 36) / sizeof(Uint32);
+ UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size - 36) >> 2;
}
else if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP20)
{
@@ -1195,7 +1197,7 @@ udf_load_partition(struct super_block *sb, lb_addr *fileset)
le16_to_cpu(((struct VirtualAllocationTable20 *)bh->b_data + UDF_I_EXT0OFFS(UDF_SB_VAT(sb)))->lengthHeader) +
UDF_I_EXT0OFFS(UDF_SB_VAT(sb));
UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size -
- UDF_SB_TYPEVIRT(sb,i).s_start_offset) / sizeof(Uint32);
+ UDF_SB_TYPEVIRT(sb,i).s_start_offset) >> 2;
udf_release_data(bh);
}
UDF_SB_PARTROOT(sb,i) = udf_get_pblock(sb, 0, i, 0);
@@ -1397,8 +1399,9 @@ udf_read_super(struct super_block *sb, void *options, int silent)
{
timestamp ts;
udf_time_to_stamp(&ts, UDF_SB_RECORDTIME(sb), 0);
- udf_info("Mounting volume '%s', timestamp %u/%02u/%u %02u:%02u\n",
- UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute);
+ udf_info("Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
+ UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute,
+ ts.typeAndTimezone);
}
if (!(sb->s_flags & MS_RDONLY))
udf_open_lvid(sb);
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index f11ccf7af..676f8b3e6 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -64,7 +64,7 @@ static void trunc(struct inode * inode)
lb_addr bloc, eloc, neloc = { 0, 0 };
Uint32 extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc;
int etype;
- int first_block = (inode->i_size + inode->i_sb->s_blocksize - 1) / inode->i_sb->s_blocksize;
+ int first_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
struct buffer_head *bh = NULL;
int adsize;
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 9ac5999b9..543d15ea9 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -1,12 +1,13 @@
#ifndef __UDF_DECL_H
#define __UDF_DECL_H
-#define UDF_VERSION_NOTICE "v0.8.9"
+#define UDF_VERSION_NOTICE "v0.8.9.3"
+
+#include <linux/udf_udf.h>
#ifdef __KERNEL__
#include <linux/types.h>
-#include <linux/udf_udf.h>
#include <linux/udf_fs.h>
#include <linux/config.h>
@@ -18,16 +19,14 @@
#error "The UDF Module Current Requires Kernel Version 2.3.7 or greater"
#endif
+#include <linux/fs.h>
/* if we're not defined, we must be compiling outside of the kernel tree */
#if !defined(CONFIG_UDF_FS) && !defined(CONFIG_UDF_FS_MODULE)
/* ... so override config */
#define CONFIG_UDF_FS_MODULE
-#include <linux/fs.h>
/* explicitly include udf_fs_sb.h and udf_fs_i.h */
#include <linux/udf_fs_sb.h>
#include <linux/udf_fs_i.h>
-#else
-#include <linux/fs.h> /* also gets udf_fs_i.h and udf_fs_sb.h */
#endif
struct dentry;
@@ -113,7 +112,6 @@ extern int udf_sync_file(struct file *, struct dentry *);
#else
#include <sys/types.h>
-#include <linux/udf_udf.h>
#endif /* __KERNEL__ */
@@ -249,7 +247,7 @@ extern Uint32 udf64_low32(Uint64);
extern Uint32 udf64_high32(Uint64);
-extern time_t *udf_stamp_to_time(time_t *, timestamp);
+extern time_t *udf_stamp_to_time(time_t *, long *, timestamp);
extern timestamp *udf_time_to_stamp(timestamp *, time_t, long);
extern time_t udf_converttime (struct ktm *);
diff --git a/fs/udf/udfend.h b/fs/udf/udfend.h
index 906a619bc..031f5b507 100644
--- a/fs/udf/udfend.h
+++ b/fs/udf/udfend.h
@@ -42,13 +42,13 @@
#define cpu_to_le32(x) (x)
#define cpu_to_le64(x) (x)
-#endif
+#endif /* __BYTE_ORDER == 0 */
-#endif
+#else /* __KERNEL__ */
-#ifdef __KERNEL__
#include <linux/string.h>
-#endif
+
+#endif /* ! __KERNEL__ */
static inline lb_addr lelb_to_cpu(lb_addr in)
{
diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c
index 715fdb4bc..3fa925f6b 100644
--- a/fs/udf/udftime.c
+++ b/fs/udf/udftime.c
@@ -18,16 +18,19 @@
Boston, MA 02111-1307, USA. */
/*
- * dgb 10/2/98: ripped this from glibc source to help convert timestamps to unix time
- * 10/4/98: added new table-based lookup after seeing how ugly the gnu code is
+ * dgb 10/02/98: ripped this from glibc source to help convert timestamps to unix time
+ * 10/04/98: added new table-based lookup after seeing how ugly the gnu code is
+ * blf 09/27/99: ripped out all the old code and inserted new table from
+ * John Brockmeyer (without leap second corrections)
+ * rewrote udf_stamp_to_time and fixed timezone accounting in
+ udf_time_to_stamp.
*/
-/* Assume that leap seconds are possible, unless told otherwise.
- If the host has a `zic' command with a `-L leapsecondfilename' option,
- then it supports leap seconds; otherwise it probably doesn't. */
-#ifndef LEAP_SECONDS_POSSIBLE
-#define LEAP_SECONDS_POSSIBLE 1
-#endif
+/*
+ * We don't take into account leap seconds. This may be correct or incorrect.
+ * For more NIST information (especially dealing with leap seconds), see:
+ * http://www.boulder.nist.gov/timefreq/pubs/bulletin/leapsecond.htm
+ */
#if defined(__linux__) && defined(__KERNEL__)
#include <linux/types.h>
@@ -35,30 +38,11 @@
#else
#include <stdio.h>
#include <sys/types.h>
+#include <sys/time.h>
#endif
#include "udfdecl.h"
-#ifndef CHAR_BIT
-#define CHAR_BIT 8
-#endif
-
-#ifndef INT_MIN
-#define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
-#endif
-#ifndef INT_MAX
-#define INT_MAX (~0 - INT_MIN)
-#endif
-
-#ifndef TIME_T_MIN
-#define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
- : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
-#endif
-#ifndef TIME_T_MAX
-#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
-#endif
-
-#define TM_YEAR_BASE 1900
#define EPOCH_YEAR 1970
#ifndef __isleap
@@ -77,70 +61,85 @@ const unsigned short int __mon_yday[2][13] =
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};
-time_t udf_converttime (struct ktm *);
-#ifndef USE_GNU_MKTIME_METHOD
-
-#define MAX_YEAR_SECONDS 68
+#define MAX_YEAR_SECONDS 69
+#define SPD 0x15180 /*3600*24*/
+#define SPY(y,l,s) (SPD * (365*y+l)+s)
time_t year_seconds[MAX_YEAR_SECONDS]= {
- 0,
- /*1971:*/ 31554000, /*1972:*/ 63090000, /*1973:*/ 94712400,
- /*1974:*/ 126248400, /*1975:*/ 157784400, /*1976:*/ 189320400,
- /*1977:*/ 220942800, /*1978:*/ 252478800, /*1979:*/ 284014800,
- /*1980:*/ 315550800, /*1981:*/ 347173200, /*1982:*/ 378709200,
- /*1983:*/ 410245200, /*1984:*/ 441781200, /*1985:*/ 473403600,
- /*1986:*/ 504939600, /*1987:*/ 536475600, /*1988:*/ 568011600,
- /*1989:*/ 599634000, /*1990:*/ 631170000, /*1991:*/ 662706000,
- /*1992:*/ 694242000, /*1993:*/ 725864400, /*1994:*/ 757400400,
- /*1995:*/ 788936400, /*1996:*/ 820472400, /*1997:*/ 852094800,
- /*1998:*/ 883630800, /*1999:*/ 915166800, /*2000:*/ 946702800,
- /*2001:*/ 978325200, /*2002:*/ 1009861200, /*2003:*/ 1041397200,
- /*2004:*/ 1072933200, /*2005:*/ 1104555600, /*2006:*/ 1136091600,
- /*2007:*/ 1167627600, /*2008:*/ 1199163600, /*2009:*/ 1230786000,
- /*2010:*/ 1262322000, /*2011:*/ 1293858000, /*2012:*/ 1325394000,
- /*2013:*/ 1357016400, /*2014:*/ 1388552400, /*2015:*/ 1420088400,
- /*2016:*/ 1451624400, /*2017:*/ 1483246800, /*2018:*/ 1514782800,
- /*2019:*/ 1546318800, /*2020:*/ 1577854800, /*2021:*/ 1609477200,
- /*2022:*/ 1641013200, /*2023:*/ 1672549200, /*2024:*/ 1704085200,
- /*2025:*/ 1735707600, /*2026:*/ 1767243600, /*2027:*/ 1798779600,
- /*2028:*/ 1830315600, /*2029:*/ 1861938000, /*2030:*/ 1893474000,
- /*2031:*/ 1925010000, /*2032:*/ 1956546000, /*2033:*/ 1988168400,
- /*2034:*/ 2019704400, /*2035:*/ 2051240400, /*2036:*/ 2082776400,
- /*2037:*/ 2114398800
+/*1970*/ SPY( 0, 0,0), SPY( 1, 0,0), SPY( 2, 0,0), SPY( 3, 1,0),
+/*1974*/ SPY( 4, 1,0), SPY( 5, 1,0), SPY( 6, 1,0), SPY( 7, 2,0),
+/*1978*/ SPY( 8, 2,0), SPY( 9, 2,0), SPY(10, 2,0), SPY(11, 3,0),
+/*1982*/ SPY(12, 3,0), SPY(13, 3,0), SPY(14, 3,0), SPY(15, 4,0),
+/*1986*/ SPY(16, 4,0), SPY(17, 4,0), SPY(18, 4,0), SPY(19, 5,0),
+/*1990*/ SPY(20, 5,0), SPY(21, 5,0), SPY(22, 5,0), SPY(23, 6,0),
+/*1994*/ SPY(24, 6,0), SPY(25, 6,0), SPY(26, 6,0), SPY(27, 7,0),
+/*1998*/ SPY(28, 7,0), SPY(29, 7,0), SPY(30, 7,0), SPY(31, 8,0),
+/*2002*/ SPY(32, 8,0), SPY(33, 8,0), SPY(34, 8,0), SPY(35, 9,0),
+/*2006*/ SPY(36, 9,0), SPY(37, 9,0), SPY(38, 9,0), SPY(39,10,0),
+/*2010*/ SPY(40,10,0), SPY(41,10,0), SPY(42,10,0), SPY(43,11,0),
+/*2014*/ SPY(44,11,0), SPY(45,11,0), SPY(46,11,0), SPY(47,12,0),
+/*2018*/ SPY(48,12,0), SPY(49,12,0), SPY(50,12,0), SPY(51,13,0),
+/*2022*/ SPY(52,13,0), SPY(53,13,0), SPY(54,13,0), SPY(55,14,0),
+/*2026*/ SPY(56,14,0), SPY(57,14,0), SPY(58,14,0), SPY(59,15,0),
+/*2030*/ SPY(60,15,0), SPY(61,15,0), SPY(62,15,0), SPY(63,16,0),
+/*2034*/ SPY(64,16,0), SPY(65,16,0), SPY(66,16,0), SPY(67,17,0),
+/*2038*/ SPY(68,17,0)
};
-time_t udf_converttime (struct ktm *tm)
-{
- time_t r;
- int yday;
-
- if ( !tm )
- return -1;
- if ( (tm->tm_year+TM_YEAR_BASE < EPOCH_YEAR) ||
- (tm->tm_year+TM_YEAR_BASE > EPOCH_YEAR+MAX_YEAR_SECONDS) )
- return -1;
- r = year_seconds[tm->tm_year-70];
-
- yday = ((__mon_yday[__isleap (tm->tm_year + TM_YEAR_BASE)]
- [tm->tm_mon-1])
- + tm->tm_mday - 1);
- r += ( ( (yday* 24) + (tm->tm_hour-1) ) * 60 + tm->tm_min ) * 60 + tm->tm_sec;
- return r;
-}
-
#ifdef __KERNEL__
-
extern struct timezone sys_tz;
+#endif
#define SECS_PER_HOUR (60 * 60)
#define SECS_PER_DAY (SECS_PER_HOUR * 24)
+time_t *
+udf_stamp_to_time(time_t *dest, long *dest_usec, timestamp src)
+{
+ int yday;
+ Uint8 type = src.typeAndTimezone >> 12;
+ Sint16 offset;
+
+ if (type == 1)
+ {
+ offset = src.typeAndTimezone << 4;
+ /* sign extent offset */
+ offset = (offset >> 4);
+ }
+ else
+ offset = 0;
+
+ if ((src.year < EPOCH_YEAR) ||
+ (src.year > EPOCH_YEAR+MAX_YEAR_SECONDS))
+ {
+ *dest = -1;
+ *dest_usec = -1;
+ return NULL;
+ }
+ *dest = year_seconds[src.year - EPOCH_YEAR];
+ *dest -= offset * 60;
+
+ yday = ((__mon_yday[__isleap (src.year)]
+ [src.month-1]) + (src.day-1));
+ *dest += ( ( (yday* 24) + src.hour ) * 60 + src.minute ) * 60 + src.second;
+ *dest_usec = src.centiseconds * 10000 + src.hundredsOfMicroseconds * 100 + src.microseconds;
+ return dest;
+}
+
+
timestamp *
udf_time_to_stamp(timestamp *dest, time_t tv_sec, long tv_usec)
{
long int days, rem, y;
const unsigned short int *ip;
- int offset = (-sys_tz.tz_minuteswest + (sys_tz.tz_dsttime ? 60 : 0));
+ Sint16 offset;
+#ifndef __KERNEL__
+ struct timeval tv;
+ struct timezone sys_tz;
+
+ gettimeofday(&tv, &sys_tz);
+#endif
+ offset = (-sys_tz.tz_minuteswest + (sys_tz.tz_dsttime ? 60 : 0));
if (!dest)
return NULL;
@@ -183,191 +182,5 @@ udf_time_to_stamp(timestamp *dest, time_t tv_sec, long tv_usec)
dest->hundredsOfMicroseconds * 100);
return dest;
}
-#endif
-
-#else
-
-static time_t ydhms_tm_diff (int, int, int, int, int, const struct ktm *);
-
-
-/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
- measured in seconds, ignoring leap seconds.
- YEAR uses the same numbering as TM->tm_year.
- All values are in range, except possibly YEAR.
- If overflow occurs, yield the low order bits of the correct answer. */
-static time_t
-ydhms_tm_diff (int year, int yday, int hour, int min, int sec, const struct ktm *tp)
-{
- time_t result;
-
- /* Compute intervening leap days correctly even if year is negative.
- Take care to avoid int overflow. time_t overflow is OK, since
- only the low order bits of the correct time_t answer are needed.
- Don't convert to time_t until after all divisions are done, since
- time_t might be unsigned. */
- int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
- int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
- int a100 = a4 / 25 - (a4 % 25 < 0);
- int b100 = b4 / 25 - (b4 % 25 < 0);
- int a400 = a100 >> 2;
- int b400 = b100 >> 2;
- int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
- time_t years = year - (time_t) tp->tm_year;
- time_t days = (365 * years + intervening_leap_days);
- result= (60 * (60 * (24 * days + (hour - tp->tm_hour))
- + (min - tp->tm_min))
- + (sec - tp->tm_sec));
-#ifdef __KERNEL__
- printk(KERN_ERR "udf: ydhms_tm_diff(%d,%d,%d,%d,%d,) returning %ld\n",
- year, yday, hour, min, sec, result);
-#endif
- return result;
-}
-
-
-/* Convert *TP to a time_t value, inverting
- the monotonic and mostly-unit-linear conversion function CONVERT.
- Use *OFFSET to keep track of a guess at the offset of the result,
- compared to what the result would be for UTC without leap seconds.
- If *OFFSET's guess is correct, only one CONVERT call is needed. */
-time_t
-udf_converttime (struct ktm *tp)
-{
- time_t t, dt, t0;
- struct ktm tm;
-
- /* The maximum number of probes (calls to CONVERT) should be enough
- to handle any combinations of time zone rule changes, solar time,
- and leap seconds. Posix.1 prohibits leap seconds, but some hosts
- have them anyway. */
- int remaining_probes = 4;
-
- /* Time requested. Copy it in case CONVERT modifies *TP; this can
- occur if TP is localtime's returned value and CONVERT is localtime. */
- int sec = tp->tm_sec;
- int min = tp->tm_min;
- int hour = tp->tm_hour;
- int mday = tp->tm_mday;
- int mon = tp->tm_mon;
- int year_requested = tp->tm_year;
- int isdst = tp->tm_isdst;
-
- /* Ensure that mon is in range, and set year accordingly. */
- int mon_remainder = mon % 12;
- int negative_mon_remainder = mon_remainder < 0;
- int mon_years = mon / 12 - negative_mon_remainder;
- int year = year_requested + mon_years;
-
- /* The other values need not be in range:
- the remaining code handles minor overflows correctly,
- assuming int and time_t arithmetic wraps around.
- Major overflows are caught at the end. */
-
- /* Calculate day of year from year, month, and day of month.
- The result need not be in range. */
- int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
- [mon_remainder + 12 * negative_mon_remainder])
- + mday - 1);
-
-#if LEAP_SECONDS_POSSIBLE
- /* Handle out-of-range seconds specially,
- since ydhms_tm_diff assumes every minute has 60 seconds. */
- int sec_requested = sec;
- if (sec < 0)
- sec = 0;
- if (59 < sec)
- sec = 59;
-#endif
-
- /* Invert CONVERT by probing. First assume the same offset as last time.
- Then repeatedly use the error to improve the guess. */
-
- tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
- tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
- /*
- t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
-
- for (t = t0;
- (dt = ydhms_tm_diff (year, yday, hour, min, sec, &tm));
- t += dt)
- if (--remaining_probes == 0)
- return -1;
- */
-
- /* Check whether tm.tm_isdst has the requested value, if any. */
- if (0 <= isdst && 0 <= tm.tm_isdst)
- {
- int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
- if (dst_diff)
- {
- /* Move two hours in the direction indicated by the disagreement,
- probe some more, and switch to a new time if found.
- The largest known fallback due to daylight savings is two hours:
- once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
- time_t ot = t - 2 * 60 * 60 * dst_diff;
- while (--remaining_probes != 0)
- {
- struct ktm otm;
- if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
- &otm)))
- {
- t = ot;
- tm = otm;
- break;
- }
- if ((ot += dt) == t)
- break; /* Avoid a redundant probe. */
- }
- }
- }
-
-
-#if LEAP_SECONDS_POSSIBLE
- if (sec_requested != tm.tm_sec)
- {
- /* Adjust time to reflect the tm_sec requested, not the normalized value.
- Also, repair any damage from a false match due to a leap second. */
- t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
- }
-#endif
-
- if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
- {
- /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
- so check for major overflows. A gross check suffices,
- since if t has overflowed, it is off by a multiple of
- TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
- the difference that is bounded by a small value. */
-
- double dyear = (double) year_requested + mon_years - tm.tm_year;
- double dday = 366 * dyear + mday;
- double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
-
- if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
- return -1;
- }
-
- *tp = tm;
-#ifdef __KERNEL__
- udf_debug("returning %ld\n", t);
-#endif
- return t;
-}
-#endif
-
-#ifdef INCLUDE_PRINT_KTM
-static void
-print_ktm (struct ktm *tp)
-{
-#ifdef __KERNEL__
- udf_debug(
-#else
- printf(
-#endif
- "%04d-%02d-%02d %02d:%02d:%02d isdst %d",
- tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
- tp->tm_hour, tp->tm_min, tp->tm_sec, tp->tm_isdst);
-}
-#endif
/* EOF */
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index c75a3a405..2f156b42a 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -676,7 +676,7 @@ unsigned ufs_bitmap_search (struct super_block * sb,
else
start = ucpi->c_frotor >> 3;
- length = howmany(uspi->s_fpg, 8) - start;
+ length = ((uspi->s_fpg + 7) >> 3) - start;
location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff + start, length,
(uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
1 << (count - 1 + (uspi->s_fpb & 7)));
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index b93d04f0b..0b23ad37f 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -168,7 +168,7 @@ int ufs_check_dir_entry (const char * function, struct inode * dir,
error_msg = "inode out of bounds";
if (error_msg != NULL)
- ufs_error (sb, function, "bad entry in directory #%lu, size %lu: %s - "
+ ufs_error (sb, function, "bad entry in directory #%lu, size %Lu: %s - "
"offset=%lu, inode=%lu, reclen=%d, namlen=%d",
dir->i_ino, dir->i_size, error_msg, offset,
(unsigned long) SWAB32(de->d_ino),
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 3d9c8f602..afcdcd600 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -610,7 +610,7 @@ void ufs_read_inode (struct inode * inode)
inode->u.ufs_i.i_gen = SWAB32(ufs_inode->ui_gen);
inode->u.ufs_i.i_shadow = SWAB32(ufs_inode->ui_u3.ui_sun.ui_shadow);
inode->u.ufs_i.i_oeftflag = SWAB32(ufs_inode->ui_u3.ui_sun.ui_oeftflag);
- inode->u.ufs_i.i_lastfrag = howmany (inode->i_size, uspi->s_fsize);
+ inode->u.ufs_i.i_lastfrag = (inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
;
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 27d404ca1..a3419a5a8 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -328,7 +328,7 @@ int ufs_read_cylinder_structures (struct super_block * sb) {
* on the device.
*/
size = uspi->s_cssize;
- blks = howmany(size, uspi->s_fsize);
+ blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift;
base = space = kmalloc(size, GFP_KERNEL);
if (!base)
goto failed;
@@ -405,7 +405,7 @@ void ufs_put_cylinder_structures (struct super_block * sb) {
uspi = sb->u.ufs_sb.s_uspi;
size = uspi->s_cssize;
- blks = howmany(size, uspi->s_fsize);
+ blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift;
base = space = (char*) sb->u.ufs_sb.s_csp[0];
for (i = 0; i < blks; i += uspi->s_fpb) {
size = uspi->s_bsize;
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c
index 99069517e..2d33bd3c9 100644
--- a/fs/ufs/truncate.c
+++ b/fs/ufs/truncate.c
@@ -59,8 +59,8 @@
* Linus
*/
-#define DIRECT_BLOCK howmany (inode->i_size, uspi->s_bsize)
-#define DIRECT_FRAGMENT howmany (inode->i_size, uspi->s_fsize)
+#define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize - 1) >> uspi->s_bshift)
+#define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift)
#define DATA_BUFFER_USED(bh) \
(atomic_read(&bh->b_count) || buffer_locked(bh))
@@ -312,7 +312,7 @@ static int ufs_trunc_dindirect (struct inode * inode, unsigned offset, u32 * p)
uspi = sb->u.ufs_sb.s_uspi;
dindirect_block = (DIRECT_BLOCK > offset)
- ? ((DIRECT_BLOCK - offset) / uspi->s_apb) : 0;
+ ? ((DIRECT_BLOCK - offset) >> uspi->s_apbshift) : 0;
retry = 0;
tmp = SWAB32(*p);
@@ -382,7 +382,7 @@ static int ufs_trunc_tindirect (struct inode * inode)
retry = 0;
tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb))
- ? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) / uspi->s_2apb) : 0;
+ ? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) >> uspi->s_2apbshift) : 0;
p = inode->u.ufs_i.i_u1.i_data + UFS_TIND_BLOCK;
if (!(tmp = SWAB32(*p)))
return 0;
@@ -471,7 +471,7 @@ void ufs_truncate (struct inode * inode)
}
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->u.ufs_i.i_lastfrag = howmany (inode->i_size, uspi->s_fsize);
+ inode->u.ufs_i.i_lastfrag = DIRECT_FRAGMENT;
mark_inode_dirty(inode);
UFSD(("EXIT\n"))
}
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index cf26773ef..049b194ee 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -14,7 +14,6 @@
* some useful macros
*/
#define in_range(b,first,len) ((b)>=(first)&&(b)<(first)+(len))
-#define howmany(x,y) (((x)+(y)-1)/(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))