diff options
Diffstat (limited to 'fs')
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); @@ -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 = @@ -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; @@ -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(¬es[0]); + bufp = storenote(¬es[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(¬es[1]); + bufp = storenote(¬es[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(¬es[2]); + bufp = storenote(¬es[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)) |