diff options
Diffstat (limited to 'fs')
240 files changed, 748 insertions, 3656 deletions
diff --git a/fs/9p/conv.c b/fs/9p/conv.c index a767e05b60b..1e898144eb7 100644 --- a/fs/9p/conv.c +++ b/fs/9p/conv.c @@ -24,7 +24,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/fs.h> diff --git a/fs/9p/error.c b/fs/9p/error.c index 981fe8ecd78..ae91555c155 100644 --- a/fs/9p/error.c +++ b/fs/9p/error.c @@ -27,7 +27,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/list.h> diff --git a/fs/9p/fcall.c b/fs/9p/fcall.c index 6f2617820a4..8556097fcda 100644 --- a/fs/9p/fcall.c +++ b/fs/9p/fcall.c @@ -24,7 +24,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/fs.h> diff --git a/fs/9p/fcprint.c b/fs/9p/fcprint.c index 583e827baeb..34b96114a28 100644 --- a/fs/9p/fcprint.c +++ b/fs/9p/fcprint.c @@ -21,7 +21,6 @@ * Boston, MA 02111-1301 USA * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/fs.h> diff --git a/fs/9p/fid.c b/fs/9p/fid.c index b7608af07ce..70492ccb438 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -20,7 +20,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/fs.h> diff --git a/fs/9p/mux.c b/fs/9p/mux.c index 12e1baa4508..90a79c78454 100644 --- a/fs/9p/mux.c +++ b/fs/9p/mux.c @@ -23,7 +23,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/fs.h> @@ -932,6 +931,8 @@ v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc, r.rcall || r.err); } while (!r.rcall && !r.err && err==-ERESTARTSYS && m->trans->status==Connected && !m->err); + + err = -ERESTARTSYS; } sigpending = 1; } diff --git a/fs/9p/trans_fd.c b/fs/9p/trans_fd.c index 94e0a7fd9fc..34d43355beb 100644 --- a/fs/9p/trans_fd.c +++ b/fs/9p/trans_fd.c @@ -25,7 +25,6 @@ * */ -#include <linux/config.h> #include <linux/in.h> #include <linux/module.h> #include <linux/net.h> diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index d37416eb579..22f7ccd58d3 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -23,7 +23,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/fs.h> diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index f867b8d3e97..450b0c1b385 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h @@ -38,7 +38,7 @@ */ extern struct file_system_type v9fs_fs_type; -extern struct address_space_operations v9fs_addr_operations; +extern const struct address_space_operations v9fs_addr_operations; extern const struct file_operations v9fs_file_operations; extern const struct file_operations v9fs_dir_operations; extern struct dentry_operations v9fs_dentry_operations; diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index efda46fb64d..9dfd259a70b 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c @@ -31,7 +31,6 @@ #include <linux/string.h> #include <linux/smp_lock.h> #include <linux/inet.h> -#include <linux/version.h> #include <linux/pagemap.h> #include <linux/idr.h> @@ -103,6 +102,6 @@ UnmapAndUnlock: return retval; } -struct address_space_operations v9fs_addr_operations = { +const struct address_space_operations v9fs_addr_operations = { .readpage = v9fs_vfs_readpage, }; diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 1a8e46084f0..c3c47eda757 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -31,7 +31,6 @@ #include <linux/string.h> #include <linux/smp_lock.h> #include <linux/inet.h> -#include <linux/version.h> #include <linux/list.h> #include <asm/uaccess.h> #include <linux/idr.h> diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 5c6bdf82146..2f580a197b8 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -300,7 +300,7 @@ clunk_fid: fid = V9FS_NOFID; put_fid: - if (fid >= 0) + if (fid != V9FS_NOFID) v9fs_put_idpool(fid, &v9ses->fidpool); kfree(fcall); diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 8b15bb22cac..63320d4e15d 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -25,7 +25,6 @@ */ #include <linux/kernel.h> -#include <linux/config.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/fs.h> diff --git a/fs/Kconfig b/fs/Kconfig index 6dc8cfd6d80..53f5c6d6112 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -326,7 +326,7 @@ source "fs/xfs/Kconfig" config OCFS2_FS tristate "OCFS2 file system support (EXPERIMENTAL)" - depends on NET && EXPERIMENTAL + depends on NET && SYSFS && EXPERIMENTAL select CONFIGFS_FS select JBD select CRC32 @@ -356,6 +356,16 @@ config OCFS2_FS - POSIX ACLs - readpages / writepages (not user visible) +config OCFS2_DEBUG_MASKLOG + bool "OCFS2 logging support" + depends on OCFS2_FS + default y + help + The ocfs2 filesystem has an extensive logging system. The system + allows selection of events to log via files in /sys/o2cb/logmask/. + This option will enlarge your kernel, but it allows debugging of + ocfs2 filesystem issues. + config MINIX_FS tristate "Minix fs support" help diff --git a/fs/Makefile b/fs/Makefile index d0ea6bfccf2..89135428a53 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -66,7 +66,6 @@ obj-$(CONFIG_MSDOS_FS) += msdos/ obj-$(CONFIG_VFAT_FS) += vfat/ obj-$(CONFIG_BFS_FS) += bfs/ obj-$(CONFIG_ISO9660_FS) += isofs/ -obj-$(CONFIG_DEVFS_FS) += devfs/ obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ obj-$(CONFIG_HFS_FS) += hfs/ obj-$(CONFIG_VXFS_FS) += freevxfs/ diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index 7b075fc397d..d3c7905b2dd 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c @@ -9,7 +9,6 @@ * * Common directory handling for ADFS */ -#include <linux/config.h> #include <linux/errno.h> #include <linux/fs.h> #include <linux/adfs_fs.h> diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index a02802a3079..534f3eecc98 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c @@ -72,7 +72,7 @@ static sector_t _adfs_bmap(struct address_space *mapping, sector_t block) return generic_block_bmap(mapping, block, adfs_get_block); } -static struct address_space_operations adfs_aops = { +static const struct address_space_operations adfs_aops = { .readpage = adfs_readpage, .writepage = adfs_writepage, .sync_page = block_sync_page, diff --git a/fs/affs/affs.h b/fs/affs/affs.h index a43a876742b..0ddd4cc0d1a 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h @@ -195,9 +195,9 @@ extern struct inode_operations affs_symlink_inode_operations; extern const struct file_operations affs_file_operations; extern const struct file_operations affs_file_operations_ofs; extern const struct file_operations affs_dir_operations; -extern struct address_space_operations affs_symlink_aops; -extern struct address_space_operations affs_aops; -extern struct address_space_operations affs_aops_ofs; +extern const struct address_space_operations affs_symlink_aops; +extern const struct address_space_operations affs_aops; +extern const struct address_space_operations affs_aops_ofs; extern struct dentry_operations affs_dentry_operations; extern struct dentry_operations affs_dentry_operations_intl; diff --git a/fs/affs/file.c b/fs/affs/file.c index 7076262af39..3de8590e4f6 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -406,7 +406,7 @@ static sector_t _affs_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,affs_get_block); } -struct address_space_operations affs_aops = { +const struct address_space_operations affs_aops = { .readpage = affs_readpage, .writepage = affs_writepage, .sync_page = block_sync_page, @@ -759,7 +759,7 @@ out: goto done; } -struct address_space_operations affs_aops_ofs = { +const struct address_space_operations affs_aops_ofs = { .readpage = affs_readpage_ofs, //.writepage = affs_writepage_ofs, //.sync_page = affs_sync_page_ofs, diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c index 426f0f094f2..f802256a593 100644 --- a/fs/affs/symlink.c +++ b/fs/affs/symlink.c @@ -66,7 +66,7 @@ fail: return err; } -struct address_space_operations affs_symlink_aops = { +const struct address_space_operations affs_symlink_aops = { .readpage = affs_symlink_readpage, }; diff --git a/fs/afs/file.c b/fs/afs/file.c index 7bb716887e2..67d6634101f 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -35,7 +35,7 @@ struct inode_operations afs_file_inode_operations = { .getattr = afs_inode_getattr, }; -struct address_space_operations afs_fs_aops = { +const struct address_space_operations afs_fs_aops = { .readpage = afs_file_readpage, .sync_page = block_sync_page, .set_page_dirty = __set_page_dirty_nobuffers, diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 72febdf9a35..e88b3b65ae4 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -69,7 +69,7 @@ extern const struct file_operations afs_dir_file_operations; /* * file.c */ -extern struct address_space_operations afs_fs_aops; +extern const struct address_space_operations afs_fs_aops; extern struct inode_operations afs_file_inode_operations; #ifdef AFS_CACHING_SUPPORT diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 08201fab26c..fcaeead9696 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -73,7 +73,7 @@ static struct inode_operations befs_dir_inode_operations = { .lookup = befs_lookup, }; -static struct address_space_operations befs_aops = { +static const struct address_space_operations befs_aops = { .readpage = befs_readpage, .sync_page = block_sync_page, .bmap = befs_bmap, @@ -325,7 +325,7 @@ befs_read_inode(struct inode *inode) if (!bh) { befs_error(sb, "unable to read inode block - " "inode = %lu", inode->i_ino); - goto unaquire_none; + goto unacquire_none; } raw_inode = (befs_inode *) bh->b_data; @@ -334,7 +334,7 @@ befs_read_inode(struct inode *inode) if (befs_check_inode(sb, raw_inode, inode->i_ino) != BEFS_OK) { befs_error(sb, "Bad inode: %lu", inode->i_ino); - goto unaquire_bh; + goto unacquire_bh; } inode->i_mode = (umode_t) fs32_to_cpu(sb, raw_inode->mode); @@ -402,17 +402,17 @@ befs_read_inode(struct inode *inode) befs_error(sb, "Inode %lu is not a regular file, " "directory or symlink. THAT IS WRONG! BeFS has no " "on disk special files", inode->i_ino); - goto unaquire_bh; + goto unacquire_bh; } brelse(bh); befs_debug(sb, "<--- befs_read_inode()"); return; - unaquire_bh: + unacquire_bh: brelse(bh); - unaquire_none: + unacquire_none: make_bad_inode(inode); befs_debug(sb, "<--- befs_read_inode() - Bad inode"); return; @@ -761,14 +761,14 @@ befs_fill_super(struct super_block *sb, void *data, int silent) printk(KERN_ERR "BeFS(%s): Unable to allocate memory for private " "portion of superblock. Bailing.\n", sb->s_id); - goto unaquire_none; + goto unacquire_none; } befs_sb = BEFS_SB(sb); memset(befs_sb, 0, sizeof(befs_sb_info)); if (!parse_options((char *) data, &befs_sb->mount_opts)) { befs_error(sb, "cannot parse mount options"); - goto unaquire_priv_sbp; + goto unacquire_priv_sbp; } befs_debug(sb, "---> befs_fill_super()"); @@ -794,7 +794,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent) if (!(bh = sb_bread(sb, sb_block))) { befs_error(sb, "unable to read superblock"); - goto unaquire_priv_sbp; + goto unacquire_priv_sbp; } /* account for offset of super block on x86 */ @@ -809,20 +809,20 @@ befs_fill_super(struct super_block *sb, void *data, int silent) } if (befs_load_sb(sb, disk_sb) != BEFS_OK) - goto unaquire_bh; + goto unacquire_bh; befs_dump_super_block(sb, disk_sb); brelse(bh); if (befs_check_sb(sb) != BEFS_OK) - goto unaquire_priv_sbp; + goto unacquire_priv_sbp; if( befs_sb->num_blocks > ~((sector_t)0) ) { befs_error(sb, "blocks count: %Lu " "is larger than the host can use", befs_sb->num_blocks); - goto unaquire_priv_sbp; + goto unacquire_priv_sbp; } /* @@ -838,7 +838,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent) if (!sb->s_root) { iput(root); befs_error(sb, "get root inode failed"); - goto unaquire_priv_sbp; + goto unacquire_priv_sbp; } /* load nls library */ @@ -860,13 +860,13 @@ befs_fill_super(struct super_block *sb, void *data, int silent) return 0; /*****************/ - unaquire_bh: + unacquire_bh: brelse(bh); - unaquire_priv_sbp: + unacquire_priv_sbp: kfree(sb->s_fs_info); - unaquire_none: + unacquire_none: sb->s_fs_info = NULL; return -EINVAL; } @@ -925,18 +925,18 @@ init_befs_fs(void) err = befs_init_inodecache(); if (err) - goto unaquire_none; + goto unacquire_none; err = register_filesystem(&befs_fs_type); if (err) - goto unaquire_inodecache; + goto unacquire_inodecache; return 0; -unaquire_inodecache: +unacquire_inodecache: befs_destroy_inodecache(); -unaquire_none: +unacquire_none: return err; } diff --git a/fs/bfs/bfs.h b/fs/bfs/bfs.h index 9d791004b21..31973bbbf05 100644 --- a/fs/bfs/bfs.h +++ b/fs/bfs/bfs.h @@ -50,7 +50,7 @@ static inline struct bfs_inode_info *BFS_I(struct inode *inode) /* file.c */ extern struct inode_operations bfs_file_inops; extern const struct file_operations bfs_file_operations; -extern struct address_space_operations bfs_aops; +extern const struct address_space_operations bfs_aops; /* dir.c */ extern struct inode_operations bfs_dir_inops; diff --git a/fs/bfs/file.c b/fs/bfs/file.c index d83cd74a2e4..3d5aca28a0a 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c @@ -153,7 +153,7 @@ static sector_t bfs_bmap(struct address_space *mapping, sector_t block) return generic_block_bmap(mapping, block, bfs_get_block); } -struct address_space_operations bfs_aops = { +const struct address_space_operations bfs_aops = { .readpage = bfs_readpage, .writepage = bfs_writepage, .sync_page = block_sync_page, diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index d0434406eae..f42e64210ee 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -84,7 +84,7 @@ static struct linux_binfmt elf_format = { .min_coredump = ELF_EXEC_PAGESIZE }; -#define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE) +#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) static int set_brk(unsigned long start, unsigned long end) { @@ -394,7 +394,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex, * <= p_memsize so it's only necessary to check p_memsz. */ k = load_addr + eppnt->p_vaddr; - if (k > TASK_SIZE || + if (BAD_ADDR(k) || eppnt->p_filesz > eppnt->p_memsz || eppnt->p_memsz > TASK_SIZE || TASK_SIZE - eppnt->p_memsz < k) { @@ -887,7 +887,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) * allowed task size. Note that p_filesz must always be * <= p_memsz so it is only necessary to check p_memsz. */ - if (k > TASK_SIZE || elf_ppnt->p_filesz > elf_ppnt->p_memsz || + if (BAD_ADDR(k) || elf_ppnt->p_filesz > elf_ppnt->p_memsz || elf_ppnt->p_memsz > TASK_SIZE || TASK_SIZE - elf_ppnt->p_memsz < k) { /* set_brk can never work. Avoid overflows. */ @@ -941,10 +941,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) interpreter, &interp_load_addr); if (BAD_ADDR(elf_entry)) { - printk(KERN_ERR "Unable to load interpreter %.128s\n", - elf_interpreter); force_sig(SIGSEGV, current); - retval = -ENOEXEC; /* Nobody gets to see this, but.. */ + retval = IS_ERR((void *)elf_entry) ? + (int)elf_entry : -EINVAL; goto out_free_dentry; } reloc_func_desc = interp_load_addr; @@ -955,8 +954,8 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) } else { elf_entry = loc->elf_ex.e_entry; if (BAD_ADDR(elf_entry)) { - send_sig(SIGSEGV, current, 0); - retval = -ENOEXEC; /* Nobody gets to see this, but.. */ + force_sig(SIGSEGV, current); + retval = -EINVAL; goto out_free_dentry; } } diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index c94d52eafd1..a62fd4018a2 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -16,7 +16,6 @@ */ #include <linux/module.h> -#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/mm.h> diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c index 00a91dc25d1..32b5d625ce9 100644 --- a/fs/binfmt_som.c +++ b/fs/binfmt_som.c @@ -32,7 +32,6 @@ #include <asm/uaccess.h> #include <asm/pgtable.h> -#include <linux/config.h> #include <linux/elf.h> diff --git a/fs/block_dev.c b/fs/block_dev.c index 028d9fb9c2d..37534573960 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -5,14 +5,12 @@ * Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE */ -#include <linux/config.h> #include <linux/init.h> #include <linux/mm.h> #include <linux/fcntl.h> #include <linux/slab.h> #include <linux/kmod.h> #include <linux/major.h> -#include <linux/devfs_fs_kernel.h> #include <linux/smp_lock.h> #include <linux/highmem.h> #include <linux/blkdev.h> @@ -741,7 +739,7 @@ static int bd_claim_by_kobject(struct block_device *bdev, void *holder, if (!bo) return -ENOMEM; - mutex_lock(&bdev->bd_mutex); + mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION); res = bd_claim(bdev, holder); if (res || !add_bd_holder(bdev, bo)) free_bd_holder(bo); @@ -766,7 +764,7 @@ static void bd_release_from_kobject(struct block_device *bdev, if (!kobj) return; - mutex_lock(&bdev->bd_mutex); + mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION); bd_release(bdev); if ((bo = del_bd_holder(bdev, kobj))) free_bd_holder(bo); @@ -824,6 +822,22 @@ struct block_device *open_by_devnum(dev_t dev, unsigned mode) EXPORT_SYMBOL(open_by_devnum); +static int +blkdev_get_partition(struct block_device *bdev, mode_t mode, unsigned flags); + +struct block_device *open_partition_by_devnum(dev_t dev, unsigned mode) +{ + struct block_device *bdev = bdget(dev); + int err = -ENOMEM; + int flags = mode & FMODE_WRITE ? O_RDWR : O_RDONLY; + if (bdev) + err = blkdev_get_partition(bdev, mode, flags); + return err ? ERR_PTR(err) : bdev; +} + +EXPORT_SYMBOL(open_partition_by_devnum); + + /* * This routine checks whether a removable media has been changed, * and invalidates all buffer-cache-entries in that case. This @@ -870,7 +884,11 @@ void bd_set_size(struct block_device *bdev, loff_t size) } EXPORT_SYMBOL(bd_set_size); -static int do_open(struct block_device *bdev, struct file *file) +static int +blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags); + +static int +do_open(struct block_device *bdev, struct file *file, unsigned int subclass) { struct module *owner = NULL; struct gendisk *disk; @@ -887,7 +905,8 @@ static int do_open(struct block_device *bdev, struct file *file) } owner = disk->fops->owner; - mutex_lock(&bdev->bd_mutex); + mutex_lock_nested(&bdev->bd_mutex, subclass); + if (!bdev->bd_openers) { bdev->bd_disk = disk; bdev->bd_contains = bdev; @@ -914,11 +933,11 @@ static int do_open(struct block_device *bdev, struct file *file) ret = -ENOMEM; if (!whole) goto out_first; - ret = blkdev_get(whole, file->f_mode, file->f_flags); + ret = blkdev_get_whole(whole, file->f_mode, file->f_flags); if (ret) goto out_first; bdev->bd_contains = whole; - mutex_lock(&whole->bd_mutex); + mutex_lock_nested(&whole->bd_mutex, BD_MUTEX_WHOLE); whole->bd_part_count++; p = disk->part[part - 1]; bdev->bd_inode->i_data.backing_dev_info = @@ -946,7 +965,8 @@ static int do_open(struct block_device *bdev, struct file *file) if (bdev->bd_invalidated) rescan_partitions(bdev->bd_disk, bdev); } else { - mutex_lock(&bdev->bd_contains->bd_mutex); + mutex_lock_nested(&bdev->bd_contains->bd_mutex, + BD_MUTEX_PARTITION); bdev->bd_contains->bd_part_count++; mutex_unlock(&bdev->bd_contains->bd_mutex); } @@ -987,11 +1007,49 @@ int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags) fake_file.f_dentry = &fake_dentry; fake_dentry.d_inode = bdev->bd_inode; - return do_open(bdev, &fake_file); + return do_open(bdev, &fake_file, BD_MUTEX_NORMAL); } EXPORT_SYMBOL(blkdev_get); +static int +blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags) +{ + /* + * This crockload is due to bad choice of ->open() type. + * It will go away. + * For now, block device ->open() routine must _not_ + * examine anything in 'inode' argument except ->i_rdev. + */ + struct file fake_file = {}; + struct dentry fake_dentry = {}; + fake_file.f_mode = mode; + fake_file.f_flags = flags; + fake_file.f_dentry = &fake_dentry; + fake_dentry.d_inode = bdev->bd_inode; + + return do_open(bdev, &fake_file, BD_MUTEX_WHOLE); +} + +static int +blkdev_get_partition(struct block_device *bdev, mode_t mode, unsigned flags) +{ + /* + * This crockload is due to bad choice of ->open() type. + * It will go away. + * For now, block device ->open() routine must _not_ + * examine anything in 'inode' argument except ->i_rdev. + */ + struct file fake_file = {}; + struct dentry fake_dentry = {}; + fake_file.f_mode = mode; + fake_file.f_flags = flags; + fake_file.f_dentry = &fake_dentry; + fake_dentry.d_inode = bdev->bd_inode; + + return do_open(bdev, &fake_file, BD_MUTEX_PARTITION); +} + static int blkdev_open(struct inode * inode, struct file * filp) { struct block_device *bdev; @@ -1007,7 +1065,7 @@ static int blkdev_open(struct inode * inode, struct file * filp) bdev = bd_acquire(inode); - res = do_open(bdev, filp); + res = do_open(bdev, filp, BD_MUTEX_NORMAL); if (res) return res; @@ -1021,13 +1079,13 @@ static int blkdev_open(struct inode * inode, struct file * filp) return res; } -int blkdev_put(struct block_device *bdev) +static int __blkdev_put(struct block_device *bdev, unsigned int subclass) { int ret = 0; struct inode *bd_inode = bdev->bd_inode; struct gendisk *disk = bdev->bd_disk; - mutex_lock(&bdev->bd_mutex); + mutex_lock_nested(&bdev->bd_mutex, subclass); lock_kernel(); if (!--bdev->bd_openers) { sync_blockdev(bdev); @@ -1037,7 +1095,8 @@ int blkdev_put(struct block_device *bdev) if (disk->fops->release) ret = disk->fops->release(bd_inode, NULL); } else { - mutex_lock(&bdev->bd_contains->bd_mutex); + mutex_lock_nested(&bdev->bd_contains->bd_mutex, + subclass + 1); bdev->bd_contains->bd_part_count--; mutex_unlock(&bdev->bd_contains->bd_mutex); } @@ -1053,9 +1112,8 @@ int blkdev_put(struct block_device *bdev) } bdev->bd_disk = NULL; bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; - if (bdev != bdev->bd_contains) { - blkdev_put(bdev->bd_contains); - } + if (bdev != bdev->bd_contains) + __blkdev_put(bdev->bd_contains, subclass + 1); bdev->bd_contains = NULL; } unlock_kernel(); @@ -1064,8 +1122,20 @@ int blkdev_put(struct block_device *bdev) return ret; } +int blkdev_put(struct block_device *bdev) +{ + return __blkdev_put(bdev, BD_MUTEX_NORMAL); +} + EXPORT_SYMBOL(blkdev_put); +int blkdev_put_partition(struct block_device *bdev) +{ + return __blkdev_put(bdev, BD_MUTEX_PARTITION); +} + +EXPORT_SYMBOL(blkdev_put_partition); + static int blkdev_close(struct inode * inode, struct file * filp) { struct block_device *bdev = I_BDEV(filp->f_mapping->host); @@ -1095,7 +1165,7 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) return blkdev_ioctl(file->f_mapping->host, file, cmd, arg); } -struct address_space_operations def_blk_aops = { +const struct address_space_operations def_blk_aops = { .readpage = blkdev_readpage, .writepage = blkdev_writepage, .sync_page = block_sync_page, diff --git a/fs/buffer.c b/fs/buffer.c index f23bb647db4..3660dcb9759 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -18,7 +18,6 @@ * async buffer flushing, 1999 Andrea Arcangeli <andrea@suse.de> */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/syscalls.h> #include <linux/fs.h> @@ -852,7 +851,7 @@ int __set_page_dirty_buffers(struct page *page) write_lock_irq(&mapping->tree_lock); if (page->mapping) { /* Race with truncate? */ if (mapping_cap_account_dirty(mapping)) - inc_page_state(nr_dirty); + __inc_zone_page_state(page, NR_FILE_DIRTY); radix_tree_tag_set(&mapping->page_tree, page_index(page), PAGECACHE_TAG_DIRTY); @@ -2598,7 +2597,7 @@ int nobh_truncate_page(struct address_space *mapping, loff_t from) unsigned offset = from & (PAGE_CACHE_SIZE-1); unsigned to; struct page *page; - struct address_space_operations *a_ops = mapping->a_ops; + const struct address_space_operations *a_ops = mapping->a_ops; char *kaddr; int ret = 0; diff --git a/fs/char_dev.c b/fs/char_dev.c index f3418f7a6e9..a4cbc6706ef 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -4,7 +4,6 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#include <linux/config.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/slab.h> @@ -14,7 +13,6 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/smp_lock.h> -#include <linux/devfs_fs_kernel.h> #include <linux/seq_file.h> #include <linux/kobject.h> diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index 031cdf29325..2e75883b7f5 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c @@ -17,7 +17,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index a6384d83fde..8f75c6f2470 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -32,8 +32,8 @@ #define TRUE 1 #endif -extern struct address_space_operations cifs_addr_ops; -extern struct address_space_operations cifs_addr_ops_smallbuf; +extern const struct address_space_operations cifs_addr_ops; +extern const struct address_space_operations cifs_addr_ops_smallbuf; /* Functions related to super block operations */ extern struct super_operations cifs_super_ops; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e9c1573f6aa..944d2b9e092 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -324,7 +324,7 @@ out: return rc; } -/* Try to reaquire byte range locks that were released when session */ +/* Try to reacquire byte range locks that were released when session */ /* to server was lost */ static int cifs_relock_file(struct cifsFileInfo *cifsFile) { @@ -1942,7 +1942,7 @@ static int cifs_prepare_write(struct file *file, struct page *page, return 0; } -struct address_space_operations cifs_addr_ops = { +const struct address_space_operations cifs_addr_ops = { .readpage = cifs_readpage, .readpages = cifs_readpages, .writepage = cifs_writepage, @@ -1959,7 +1959,7 @@ struct address_space_operations cifs_addr_ops = { * contain the header plus one complete page of data. Otherwise, we need * to leave cifs_readpages out of the address space operations. */ -struct address_space_operations cifs_addr_ops_smallbuf = { +const struct address_space_operations cifs_addr_ops_smallbuf = { .readpage = cifs_readpage, .writepage = cifs_writepage, .writepages = cifs_writepages, diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index 7caee8d8ea3..803aacf0d49 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -28,7 +28,6 @@ #include <linux/delay.h> #include <linux/skbuff.h> #include <linux/proc_fs.h> -#include <linux/devfs_fs_kernel.h> #include <linux/vmalloc.h> #include <linux/fs.h> #include <linux/file.h> @@ -365,22 +364,12 @@ static int init_coda_psdev(void) err = PTR_ERR(coda_psdev_class); goto out_chrdev; } - devfs_mk_dir ("coda"); - for (i = 0; i < MAX_CODADEVS; i++) { + for (i = 0; i < MAX_CODADEVS; i++) class_device_create(coda_psdev_class, NULL, MKDEV(CODA_PSDEV_MAJOR,i), NULL, "cfs%d", i); - err = devfs_mk_cdev(MKDEV(CODA_PSDEV_MAJOR, i), - S_IFCHR|S_IRUSR|S_IWUSR, "coda/%d", i); - if (err) - goto out_class; - } coda_sysctl_init(); goto out; -out_class: - for (i = 0; i < MAX_CODADEVS; i++) - class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); - class_destroy(coda_psdev_class); out_chrdev: unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); out: @@ -419,12 +408,9 @@ static int __init init_coda(void) } return 0; out: - for (i = 0; i < MAX_CODADEVS; i++) { + for (i = 0; i < MAX_CODADEVS; i++) class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); - devfs_remove("coda/%d", i); - } class_destroy(coda_psdev_class); - devfs_remove("coda"); unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); coda_sysctl_clean(); out1: @@ -441,12 +427,9 @@ static void __exit exit_coda(void) if ( err != 0 ) { printk("coda: failed to unregister filesystem\n"); } - for (i = 0; i < MAX_CODADEVS; i++) { + for (i = 0; i < MAX_CODADEVS; i++) class_device_destroy(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR, i)); - devfs_remove("coda/%d", i); - } class_destroy(coda_psdev_class); - devfs_remove("coda"); unregister_chrdev(CODA_PSDEV_MAJOR, "coda"); coda_sysctl_clean(); coda_destroy_inodecache(); diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c index b35e5bbd9c9..76e00a65a75 100644 --- a/fs/coda/symlink.c +++ b/fs/coda/symlink.c @@ -50,6 +50,6 @@ fail: return error; } -struct address_space_operations coda_symlink_aops = { +const struct address_space_operations coda_symlink_aops = { .readpage = coda_symlink_filler, }; diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c index f0b10757288..1c82e9a7d7c 100644 --- a/fs/coda/sysctl.c +++ b/fs/coda/sysctl.c @@ -11,7 +11,6 @@ * */ -#include <linux/config.h> #include <linux/time.h> #include <linux/mm.h> #include <linux/sysctl.h> diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index d8ecfedef18..4063a939697 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -10,7 +10,6 @@ * ioctls. */ -#include <linux/config.h> #include <linux/types.h> #include <linux/compat.h> #include <linux/kernel.h> @@ -44,7 +43,6 @@ #include <linux/loop.h> #include <linux/auto_fs.h> #include <linux/auto_fs4.h> -#include <linux/devfs_fs.h> #include <linux/tty.h> #include <linux/vt_kern.h> #include <linux/fb.h> diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 207f8006fd6..df025453dd9 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -211,7 +211,7 @@ static void remove_dir(struct dentry * d) struct configfs_dirent * sd; sd = d->d_fsdata; - list_del_init(&sd->s_sibling); + list_del_init(&sd->s_sibling); configfs_put(sd); if (d->d_inode) simple_rmdir(parent->d_inode,d); @@ -330,7 +330,7 @@ static int configfs_detach_prep(struct dentry *dentry) ret = configfs_detach_prep(sd->s_dentry); if (!ret) - continue; + continue; } else ret = -ENOTEMPTY; @@ -931,7 +931,7 @@ int configfs_rename_dir(struct config_item * item, const char *new_name) new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); if (!IS_ERR(new_dentry)) { - if (!new_dentry->d_inode) { + if (!new_dentry->d_inode) { error = config_item_set_name(item, "%s", new_name); if (!error) { d_add(new_dentry, NULL); diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index c153bd9534c..e14488ca641 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -38,7 +38,7 @@ extern struct super_block * configfs_sb; -static struct address_space_operations configfs_aops = { +static const struct address_space_operations configfs_aops = { .readpage = simple_readpage, .prepare_write = simple_prepare_write, .commit_write = simple_commit_write diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c index e5512e295cf..fb65e0800a8 100644 --- a/fs/configfs/symlink.c +++ b/fs/configfs/symlink.c @@ -66,7 +66,7 @@ static void fill_item_path(struct config_item * item, char * buffer, int length) } static int create_link(struct config_item *parent_item, - struct config_item *item, + struct config_item *item, struct dentry *dentry) { struct configfs_dirent *target_sd = item->ci_dentry->d_fsdata; diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index c45d7386080..223c0431042 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -30,7 +30,7 @@ static struct super_operations cramfs_ops; static struct inode_operations cramfs_dir_inode_operations; static const struct file_operations cramfs_directory_operations; -static struct address_space_operations cramfs_aops; +static const struct address_space_operations cramfs_aops; static DEFINE_MUTEX(read_mutex); @@ -501,7 +501,7 @@ static int cramfs_readpage(struct file *file, struct page * page) return 0; } -static struct address_space_operations cramfs_aops = { +static const struct address_space_operations cramfs_aops = { .readpage = cramfs_readpage }; diff --git a/fs/dcache.c b/fs/dcache.c index 48b44a714b3..1b4a3a34ec5 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -14,7 +14,6 @@ * the dcache entry is deleted or garbage collected. */ -#include <linux/config.h> #include <linux/syscalls.h> #include <linux/string.h> #include <linux/mm.h> @@ -39,7 +38,7 @@ int sysctl_vfs_cache_pressure __read_mostly = 100; EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lock); -static seqlock_t rename_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED; +static __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); EXPORT_SYMBOL(dcache_lock); @@ -1340,10 +1339,10 @@ void d_move(struct dentry * dentry, struct dentry * target) */ if (target < dentry) { spin_lock(&target->d_lock); - spin_lock(&dentry->d_lock); + spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); } else { spin_lock(&dentry->d_lock); - spin_lock(&target->d_lock); + spin_lock_nested(&target->d_lock, DENTRY_D_LOCK_NESTED); } /* Move the dentry to the target hash queue, if on different bucket */ diff --git a/fs/dcookies.c b/fs/dcookies.c index 8749339bf4f..0c4b0674854 100644 --- a/fs/dcookies.c +++ b/fs/dcookies.c @@ -12,7 +12,6 @@ * to the pair and can be looked up from userspace. */ -#include <linux/config.h> #include <linux/syscalls.h> #include <linux/module.h> #include <linux/slab.h> diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 66a505422e5..39640fd0345 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -13,7 +13,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/pagemap.h> diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 6fa1e04f841..e8ae3042b80 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -16,7 +16,6 @@ /* uncomment to get debug messages from the debug filesystem, ah the irony. */ /* #define DEBUG */ -#include <linux/config.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/mount.h> diff --git a/fs/devfs/Makefile b/fs/devfs/Makefile deleted file mode 100644 index 6dd8d1245e2..00000000000 --- a/fs/devfs/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for the linux devfs-filesystem routines. -# - -obj-$(CONFIG_DEVFS_FS) += devfs.o - -devfs-objs := base.o util.o - diff --git a/fs/devfs/base.c b/fs/devfs/base.c deleted file mode 100644 index 51a97f13274..00000000000 --- a/fs/devfs/base.c +++ /dev/null @@ -1,2836 +0,0 @@ -/* devfs (Device FileSystem) driver. - - Copyright (C) 1998-2002 Richard Gooch - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Richard Gooch may be reached by email at rgooch@atnf.csiro.au - The postal address is: - Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. - - ChangeLog - - 19980110 Richard Gooch <rgooch@atnf.csiro.au> - Original version. - v0.1 - 19980111 Richard Gooch <rgooch@atnf.csiro.au> - Created per-fs inode table rather than using inode->u.generic_ip - v0.2 - 19980111 Richard Gooch <rgooch@atnf.csiro.au> - Created .epoch inode which has a ctime of 0. - Fixed loss of named pipes when dentries lost. - Fixed loss of inode data when devfs_register() follows mknod(). - v0.3 - 19980111 Richard Gooch <rgooch@atnf.csiro.au> - Fix for when compiling with CONFIG_KERNELD. - 19980112 Richard Gooch <rgooch@atnf.csiro.au> - Fix for readdir() which sometimes didn't show entries. - Added <<tolerant>> option to <devfs_register>. - v0.4 - 19980113 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_fill_file> function. - v0.5 - 19980115 Richard Gooch <rgooch@atnf.csiro.au> - Added subdirectory support. Major restructuring. - 19980116 Richard Gooch <rgooch@atnf.csiro.au> - Fixed <find_by_dev> to not search major=0,minor=0. - Added symlink support. - v0.6 - 19980120 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_mk_dir> function and support directory unregister - 19980120 Richard Gooch <rgooch@atnf.csiro.au> - Auto-ownership uses real uid/gid rather than effective uid/gid. - v0.7 - 19980121 Richard Gooch <rgooch@atnf.csiro.au> - Supported creation of sockets. - v0.8 - 19980122 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFS_FL_HIDE_UNREG flag. - Interface change to <devfs_mk_symlink>. - Created <devfs_symlink> to support symlink(2). - v0.9 - 19980123 Richard Gooch <rgooch@atnf.csiro.au> - Added check to <devfs_fill_file> to check inode is in devfs. - Added optional traversal of symlinks. - v0.10 - 19980124 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_get_flags> and <devfs_set_flags>. - v0.11 - 19980125 C. Scott Ananian <cananian@alumni.princeton.edu> - Created <devfs_find_handle>. - 19980125 Richard Gooch <rgooch@atnf.csiro.au> - Allow removal of symlinks. - v0.12 - 19980125 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_set_symlink_destination>. - 19980126 Richard Gooch <rgooch@atnf.csiro.au> - Moved DEVFS_SUPER_MAGIC into header file. - Added DEVFS_FL_HIDE flag. - Created <devfs_get_maj_min>. - Created <devfs_get_handle_from_inode>. - Fixed minor bug in <find_by_dev>. - 19980127 Richard Gooch <rgooch@atnf.csiro.au> - Changed interface to <find_by_dev>, <find_entry>, - <devfs_unregister>, <devfs_fill_file> and <devfs_find_handle>. - Fixed inode times when symlink created with symlink(2). - v0.13 - 19980129 C. Scott Ananian <cananian@alumni.princeton.edu> - Exported <devfs_set_symlink_destination>, <devfs_get_maj_min> - and <devfs_get_handle_from_inode>. - 19980129 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_unlink> to support unlink(2). - v0.14 - 19980129 Richard Gooch <rgooch@atnf.csiro.au> - Fixed kerneld support for entries in devfs subdirectories. - 19980130 Richard Gooch <rgooch@atnf.csiro.au> - Bugfixes in <call_kerneld>. - v0.15 - 19980207 Richard Gooch <rgooch@atnf.csiro.au> - Call kerneld when looking up unregistered entries. - v0.16 - 19980326 Richard Gooch <rgooch@atnf.csiro.au> - Modified interface to <devfs_find_handle> for symlink traversal. - v0.17 - 19980331 Richard Gooch <rgooch@atnf.csiro.au> - Fixed persistence bug with device numbers for manually created - device files. - Fixed problem with recreating symlinks with different content. - v0.18 - 19980401 Richard Gooch <rgooch@atnf.csiro.au> - Changed to CONFIG_KMOD. - Hide entries which are manually unlinked. - Always invalidate devfs dentry cache when registering entries. - Created <devfs_rmdir> to support rmdir(2). - Ensure directories created by <devfs_mk_dir> are visible. - v0.19 - 19980402 Richard Gooch <rgooch@atnf.csiro.au> - Invalidate devfs dentry cache when making directories. - Invalidate devfs dentry cache when removing entries. - Fixed persistence bug with fifos. - v0.20 - 19980421 Richard Gooch <rgooch@atnf.csiro.au> - Print process command when debugging kerneld/kmod. - Added debugging for register/unregister/change operations. - 19980422 Richard Gooch <rgooch@atnf.csiro.au> - Added "devfs=" boot options. - v0.21 - 19980426 Richard Gooch <rgooch@atnf.csiro.au> - No longer lock/unlock superblock in <devfs_put_super>. - Drop negative dentries when they are released. - Manage dcache more efficiently. - v0.22 - 19980427 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFS_FL_AUTO_DEVNUM flag. - v0.23 - 19980430 Richard Gooch <rgooch@atnf.csiro.au> - No longer set unnecessary methods. - v0.24 - 19980504 Richard Gooch <rgooch@atnf.csiro.au> - Added PID display to <call_kerneld> debugging message. - Added "after" debugging message to <call_kerneld>. - 19980519 Richard Gooch <rgooch@atnf.csiro.au> - Added "diread" and "diwrite" boot options. - 19980520 Richard Gooch <rgooch@atnf.csiro.au> - Fixed persistence problem with permissions. - v0.25 - 19980602 Richard Gooch <rgooch@atnf.csiro.au> - Support legacy device nodes. - Fixed bug where recreated inodes were hidden. - v0.26 - 19980602 Richard Gooch <rgooch@atnf.csiro.au> - Improved debugging in <get_vfs_inode>. - 19980607 Richard Gooch <rgooch@atnf.csiro.au> - No longer free old dentries in <devfs_mk_dir>. - Free all dentries for a given entry when deleting inodes. - v0.27 - 19980627 Richard Gooch <rgooch@atnf.csiro.au> - Limit auto-device numbering to majors 128 to 239. - v0.28 - 19980629 Richard Gooch <rgooch@atnf.csiro.au> - Fixed inode times persistence problem. - v0.29 - 19980704 Richard Gooch <rgooch@atnf.csiro.au> - Fixed spelling in <devfs_readlink> debug. - Fixed bug in <devfs_setup> parsing "dilookup". - v0.30 - 19980705 Richard Gooch <rgooch@atnf.csiro.au> - Fixed devfs inode leak when manually recreating inodes. - Fixed permission persistence problem when recreating inodes. - v0.31 - 19980727 Richard Gooch <rgooch@atnf.csiro.au> - Removed harmless "unused variable" compiler warning. - Fixed modes for manually recreated device nodes. - v0.32 - 19980728 Richard Gooch <rgooch@atnf.csiro.au> - Added NULL devfs inode warning in <devfs_read_inode>. - Force all inode nlink values to 1. - v0.33 - 19980730 Richard Gooch <rgooch@atnf.csiro.au> - Added "dimknod" boot option. - Set inode nlink to 0 when freeing dentries. - Fixed modes for manually recreated symlinks. - v0.34 - 19980802 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bugs in recreated directories and symlinks. - v0.35 - 19980806 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bugs in recreated device nodes. - 19980807 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bug in currently unused <devfs_get_handle_from_inode>. - Defined new <devfs_handle_t> type. - Improved debugging when getting entries. - Fixed bug where directories could be emptied. - v0.36 - 19980809 Richard Gooch <rgooch@atnf.csiro.au> - Replaced dummy .epoch inode with .devfsd character device. - 19980810 Richard Gooch <rgooch@atnf.csiro.au> - Implemented devfsd protocol revision 0. - v0.37 - 19980819 Richard Gooch <rgooch@atnf.csiro.au> - Added soothing message to warning in <devfs_d_iput>. - v0.38 - 19980829 Richard Gooch <rgooch@atnf.csiro.au> - Use GCC extensions for structure initialisations. - Implemented async open notification. - Incremented devfsd protocol revision to 1. - v0.39 - 19980908 Richard Gooch <rgooch@atnf.csiro.au> - Moved async open notification to end of <devfs_open>. - v0.40 - 19980910 Richard Gooch <rgooch@atnf.csiro.au> - Prepended "/dev/" to module load request. - Renamed <call_kerneld> to <call_kmod>. - v0.41 - 19980910 Richard Gooch <rgooch@atnf.csiro.au> - Fixed typo "AYSNC" -> "ASYNC". - v0.42 - 19980910 Richard Gooch <rgooch@atnf.csiro.au> - Added open flag for files. - v0.43 - 19980927 Richard Gooch <rgooch@atnf.csiro.au> - Set i_blocks=0 and i_blksize=1024 in <devfs_read_inode>. - v0.44 - 19981005 Richard Gooch <rgooch@atnf.csiro.au> - Added test for empty <<name>> in <devfs_find_handle>. - Renamed <generate_path> to <devfs_generate_path> and published. - v0.45 - 19981006 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_get_fops>. - v0.46 - 19981007 Richard Gooch <rgooch@atnf.csiro.au> - Limit auto-device numbering to majors 144 to 239. - v0.47 - 19981010 Richard Gooch <rgooch@atnf.csiro.au> - Updated <devfs_follow_link> for VFS change in 2.1.125. - v0.48 - 19981022 Richard Gooch <rgooch@atnf.csiro.au> - Created DEVFS_ FL_COMPAT flag. - v0.49 - 19981023 Richard Gooch <rgooch@atnf.csiro.au> - Created "nocompat" boot option. - v0.50 - 19981025 Richard Gooch <rgooch@atnf.csiro.au> - Replaced "mount" boot option with "nomount". - v0.51 - 19981110 Richard Gooch <rgooch@atnf.csiro.au> - Created "only" boot option. - v0.52 - 19981112 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFS_FL_REMOVABLE flag. - v0.53 - 19981114 Richard Gooch <rgooch@atnf.csiro.au> - Only call <scan_dir_for_removable> on first call to - <devfs_readdir>. - v0.54 - 19981205 Richard Gooch <rgooch@atnf.csiro.au> - Updated <devfs_rmdir> for VFS change in 2.1.131. - v0.55 - 19981218 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_mk_compat>. - 19981220 Richard Gooch <rgooch@atnf.csiro.au> - Check for partitions on removable media in <devfs_lookup>. - v0.56 - 19990118 Richard Gooch <rgooch@atnf.csiro.au> - Added support for registering regular files. - Created <devfs_set_file_size>. - Update devfs inodes from entries if not changed through FS. - v0.57 - 19990124 Richard Gooch <rgooch@atnf.csiro.au> - Fixed <devfs_fill_file> to only initialise temporary inodes. - Trap for NULL fops in <devfs_register>. - Return -ENODEV in <devfs_fill_file> for non-driver inodes. - v0.58 - 19990126 Richard Gooch <rgooch@atnf.csiro.au> - Switched from PATH_MAX to DEVFS_PATHLEN. - v0.59 - 19990127 Richard Gooch <rgooch@atnf.csiro.au> - Created "nottycompat" boot option. - v0.60 - 19990318 Richard Gooch <rgooch@atnf.csiro.au> - Fixed <devfsd_read> to not overrun event buffer. - v0.61 - 19990329 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_auto_unregister>. - v0.62 - 19990330 Richard Gooch <rgooch@atnf.csiro.au> - Don't return unregistred entries in <devfs_find_handle>. - Panic in <devfs_unregister> if entry unregistered. - 19990401 Richard Gooch <rgooch@atnf.csiro.au> - Don't panic in <devfs_auto_unregister> for duplicates. - v0.63 - 19990402 Richard Gooch <rgooch@atnf.csiro.au> - Don't unregister already unregistered entries in <unregister>. - v0.64 - 19990510 Richard Gooch <rgooch@atnf.csiro.au> - Disable warning messages when unable to read partition table for - removable media. - v0.65 - 19990512 Richard Gooch <rgooch@atnf.csiro.au> - Updated <devfs_lookup> for VFS change in 2.3.1-pre1. - Created "oops-on-panic" boot option. - Improved debugging in <devfs_register> and <devfs_unregister>. - v0.66 - 19990519 Richard Gooch <rgooch@atnf.csiro.au> - Added documentation for some functions. - 19990525 Richard Gooch <rgooch@atnf.csiro.au> - Removed "oops-on-panic" boot option: now always Oops. - v0.67 - 19990531 Richard Gooch <rgooch@atnf.csiro.au> - Improved debugging in <devfs_register>. - v0.68 - 19990604 Richard Gooch <rgooch@atnf.csiro.au> - Added "diunlink" and "nokmod" boot options. - Removed superfluous warning message in <devfs_d_iput>. - v0.69 - 19990611 Richard Gooch <rgooch@atnf.csiro.au> - Took account of change to <d_alloc_root>. - v0.70 - 19990614 Richard Gooch <rgooch@atnf.csiro.au> - Created separate event queue for each mounted devfs. - Removed <devfs_invalidate_dcache>. - Created new ioctl()s. - Incremented devfsd protocol revision to 3. - Fixed bug when re-creating directories: contents were lost. - Block access to inodes until devfsd updates permissions. - 19990615 Richard Gooch <rgooch@atnf.csiro.au> - Support 2.2.x kernels. - v0.71 - 19990623 Richard Gooch <rgooch@atnf.csiro.au> - Switched to sending process uid/gid to devfsd. - Renamed <call_kmod> to <try_modload>. - Added DEVFSD_NOTIFY_LOOKUP event. - 19990624 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFSD_NOTIFY_CHANGE event. - Incremented devfsd protocol revision to 4. - v0.72 - 19990713 Richard Gooch <rgooch@atnf.csiro.au> - Return EISDIR rather than EINVAL for read(2) on directories. - v0.73 - 19990809 Richard Gooch <rgooch@atnf.csiro.au> - Changed <devfs_setup> to new __init scheme. - v0.74 - 19990901 Richard Gooch <rgooch@atnf.csiro.au> - Changed remaining function declarations to new __init scheme. - v0.75 - 19991013 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_get_info>, <devfs_set_info>, - <devfs_get_first_child> and <devfs_get_next_sibling>. - Added <<dir>> parameter to <devfs_register>, <devfs_mk_compat>, - <devfs_mk_dir> and <devfs_find_handle>. - Work sponsored by SGI. - v0.76 - 19991017 Richard Gooch <rgooch@atnf.csiro.au> - Allow multiple unregistrations. - Work sponsored by SGI. - v0.77 - 19991026 Richard Gooch <rgooch@atnf.csiro.au> - Added major and minor number to devfsd protocol. - Incremented devfsd protocol revision to 5. - Work sponsored by SGI. - v0.78 - 19991030 Richard Gooch <rgooch@atnf.csiro.au> - Support info pointer for all devfs entry types. - Added <<info>> parameter to <devfs_mk_dir> and - <devfs_mk_symlink>. - Work sponsored by SGI. - v0.79 - 19991031 Richard Gooch <rgooch@atnf.csiro.au> - Support "../" when searching devfs namespace. - Work sponsored by SGI. - v0.80 - 19991101 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_get_unregister_slave>. - Work sponsored by SGI. - v0.81 - 19991103 Richard Gooch <rgooch@atnf.csiro.au> - Exported <devfs_get_parent>. - Work sponsored by SGI. - v0.82 - 19991104 Richard Gooch <rgooch@atnf.csiro.au> - Removed unused <devfs_set_symlink_destination>. - 19991105 Richard Gooch <rgooch@atnf.csiro.au> - Do not hide entries from devfsd or children. - Removed DEVFS_ FL_TTY_COMPAT flag. - Removed "nottycompat" boot option. - Removed <devfs_mk_compat>. - Work sponsored by SGI. - v0.83 - 19991107 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFS_FL_WAIT flag. - Work sponsored by SGI. - v0.84 - 19991107 Richard Gooch <rgooch@atnf.csiro.au> - Support new "disc" naming scheme in <get_removable_partition>. - Allow NULL fops in <devfs_register>. - Work sponsored by SGI. - v0.85 - 19991110 Richard Gooch <rgooch@atnf.csiro.au> - Fall back to major table if NULL fops given to <devfs_register>. - Work sponsored by SGI. - v0.86 - 19991204 Richard Gooch <rgooch@atnf.csiro.au> - Support fifos when unregistering. - Work sponsored by SGI. - v0.87 - 19991209 Richard Gooch <rgooch@atnf.csiro.au> - Removed obsolete DEVFS_ FL_COMPAT and DEVFS_ FL_TOLERANT flags. - Work sponsored by SGI. - v0.88 - 19991214 Richard Gooch <rgooch@atnf.csiro.au> - Removed kmod support. - Work sponsored by SGI. - v0.89 - 19991216 Richard Gooch <rgooch@atnf.csiro.au> - Improved debugging in <get_vfs_inode>. - Ensure dentries created by devfsd will be cleaned up. - Work sponsored by SGI. - v0.90 - 19991223 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_get_name>. - Work sponsored by SGI. - v0.91 - 20000203 Richard Gooch <rgooch@atnf.csiro.au> - Ported to kernel 2.3.42. - Removed <devfs_fill_file>. - Work sponsored by SGI. - v0.92 - 20000306 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFS_ FL_NO_PERSISTENCE flag. - Removed unnecessary call to <update_devfs_inode_from_entry> in - <devfs_readdir>. - Work sponsored by SGI. - v0.93 - 20000413 Richard Gooch <rgooch@atnf.csiro.au> - Set inode->i_size to correct size for symlinks. - 20000414 Richard Gooch <rgooch@atnf.csiro.au> - Only give lookup() method to directories to comply with new VFS - assumptions. - Work sponsored by SGI. - 20000415 Richard Gooch <rgooch@atnf.csiro.au> - Remove unnecessary tests in symlink methods. - Don't kill existing block ops in <devfs_read_inode>. - Work sponsored by SGI. - v0.94 - 20000424 Richard Gooch <rgooch@atnf.csiro.au> - Don't create missing directories in <devfs_find_handle>. - Work sponsored by SGI. - v0.95 - 20000430 Richard Gooch <rgooch@atnf.csiro.au> - Added CONFIG_DEVFS_MOUNT. - Work sponsored by SGI. - v0.96 - 20000608 Richard Gooch <rgooch@atnf.csiro.au> - Disabled multi-mount capability (use VFS bindings instead). - Work sponsored by SGI. - v0.97 - 20000610 Richard Gooch <rgooch@atnf.csiro.au> - Switched to FS_SINGLE to disable multi-mounts. - 20000612 Richard Gooch <rgooch@atnf.csiro.au> - Removed module support. - Removed multi-mount code. - Removed compatibility macros: VFS has changed too much. - Work sponsored by SGI. - v0.98 - 20000614 Richard Gooch <rgooch@atnf.csiro.au> - Merged devfs inode into devfs entry. - Work sponsored by SGI. - v0.99 - 20000619 Richard Gooch <rgooch@atnf.csiro.au> - Removed dead code in <devfs_register> which used to call - <free_dentries>. - Work sponsored by SGI. - v0.100 - 20000621 Richard Gooch <rgooch@atnf.csiro.au> - Changed interface to <devfs_register>. - Work sponsored by SGI. - v0.101 - 20000622 Richard Gooch <rgooch@atnf.csiro.au> - Simplified interface to <devfs_mk_symlink> and <devfs_mk_dir>. - Simplified interface to <devfs_find_handle>. - Work sponsored by SGI. - v0.102 - 20010519 Richard Gooch <rgooch@atnf.csiro.au> - Ensure <devfs_generate_path> terminates string for root entry. - Exported <devfs_get_name> to modules. - 20010520 Richard Gooch <rgooch@atnf.csiro.au> - Make <devfs_mk_symlink> send events to devfsd. - Cleaned up option processing in <devfs_setup>. - 20010521 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bugs in handling symlinks: could leak or cause Oops. - 20010522 Richard Gooch <rgooch@atnf.csiro.au> - Cleaned up directory handling by separating fops. - v0.103 - 20010601 Richard Gooch <rgooch@atnf.csiro.au> - Fixed handling of inverted options in <devfs_setup>. - v0.104 - 20010604 Richard Gooch <rgooch@atnf.csiro.au> - Adjusted <try_modload> to account for <devfs_generate_path> fix. - v0.105 - 20010617 Richard Gooch <rgooch@atnf.csiro.au> - Answered question posed by Al Viro and removed his comments. - Moved setting of registered flag after other fields are changed. - Fixed race between <devfsd_close> and <devfsd_notify_one>. - Global VFS changes added bogus BKL to <devfsd_close>: removed. - Widened locking in <devfs_readlink> and <devfs_follow_link>. - Replaced <devfsd_read> stack usage with <devfsd_ioctl> kmalloc. - Simplified locking in <devfsd_ioctl> and fixed memory leak. - v0.106 - 20010709 Richard Gooch <rgooch@atnf.csiro.au> - Removed broken devnum allocation and use <devfs_alloc_devnum>. - Fixed old devnum leak by calling new <devfs_dealloc_devnum>. - v0.107 - 20010712 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bug in <devfs_setup> which could hang boot process. - v0.108 - 20010730 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFSD_NOTIFY_DELETE event. - 20010801 Richard Gooch <rgooch@atnf.csiro.au> - Removed #include <asm/segment.h>. - v0.109 - 20010807 Richard Gooch <rgooch@atnf.csiro.au> - Fixed inode table races by removing it and using - inode->u.generic_ip instead. - Moved <devfs_read_inode> into <get_vfs_inode>. - Moved <devfs_write_inode> into <devfs_notify_change>. - v0.110 - 20010808 Richard Gooch <rgooch@atnf.csiro.au> - Fixed race in <devfs_do_symlink> for uni-processor. - v0.111 - 20010818 Richard Gooch <rgooch@atnf.csiro.au> - Removed remnant of multi-mount support in <devfs_mknod>. - Removed unused DEVFS_FL_SHOW_UNREG flag. - v0.112 - 20010820 Richard Gooch <rgooch@atnf.csiro.au> - Removed nlink field from struct devfs_inode. - v0.113 - 20010823 Richard Gooch <rgooch@atnf.csiro.au> - Replaced BKL with global rwsem to protect symlink data (quick - and dirty hack). - v0.114 - 20010827 Richard Gooch <rgooch@atnf.csiro.au> - Replaced global rwsem for symlink with per-link refcount. - v0.115 - 20010919 Richard Gooch <rgooch@atnf.csiro.au> - Set inode->i_mapping->a_ops for block nodes in <get_vfs_inode>. - v0.116 - 20011008 Richard Gooch <rgooch@atnf.csiro.au> - Fixed overrun in <devfs_link> by removing function (not needed). - 20011009 Richard Gooch <rgooch@atnf.csiro.au> - Fixed buffer underrun in <try_modload>. - 20011029 Richard Gooch <rgooch@atnf.csiro.au> - Fixed race in <devfsd_ioctl> when setting event mask. - 20011114 Richard Gooch <rgooch@atnf.csiro.au> - First release of new locking code. - v1.0 - 20011117 Richard Gooch <rgooch@atnf.csiro.au> - Discard temporary buffer, now use "%s" for dentry names. - 20011118 Richard Gooch <rgooch@atnf.csiro.au> - Don't generate path in <try_modload>: use fake entry instead. - Use "existing" directory in <_devfs_make_parent_for_leaf>. - 20011122 Richard Gooch <rgooch@atnf.csiro.au> - Use slab cache rather than fixed buffer for devfsd events. - v1.1 - 20011125 Richard Gooch <rgooch@atnf.csiro.au> - Send DEVFSD_NOTIFY_REGISTERED events in <devfs_mk_dir>. - 20011127 Richard Gooch <rgooch@atnf.csiro.au> - Fixed locking bug in <devfs_d_revalidate_wait> due to typo. - Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from - devfsd or children. - v1.2 - 20011202 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bug in <devfsd_read>: was dereferencing freed pointer. - v1.3 - 20011203 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bug in <devfsd_close>: was dereferencing freed pointer. - Added process group check for devfsd privileges. - v1.4 - 20011204 Richard Gooch <rgooch@atnf.csiro.au> - Use SLAB_ATOMIC in <devfsd_notify_de> from <devfs_d_delete>. - v1.5 - 20011211 Richard Gooch <rgooch@atnf.csiro.au> - Return old entry in <devfs_mk_dir> for 2.4.x kernels. - 20011212 Richard Gooch <rgooch@atnf.csiro.au> - Increment refcount on module in <check_disc_changed>. - 20011215 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_get_handle> and exported <devfs_put>. - Increment refcount on module in <devfs_get_ops>. - Created <devfs_put_ops>. - v1.6 - 20011216 Richard Gooch <rgooch@atnf.csiro.au> - Added poisoning to <devfs_put>. - Improved debugging messages. - v1.7 - 20011221 Richard Gooch <rgooch@atnf.csiro.au> - Corrected (made useful) debugging message in <unregister>. - Moved <kmem_cache_create> in <mount_devfs_fs> to <init_devfs_fs> - 20011224 Richard Gooch <rgooch@atnf.csiro.au> - Added magic number to guard against scribbling drivers. - 20011226 Richard Gooch <rgooch@atnf.csiro.au> - Only return old entry in <devfs_mk_dir> if a directory. - Defined macros for error and debug messages. - v1.8 - 20020113 Richard Gooch <rgooch@atnf.csiro.au> - Fixed (rare, old) race in <devfs_lookup>. - v1.9 - 20020120 Richard Gooch <rgooch@atnf.csiro.au> - Fixed deadlock bug in <devfs_d_revalidate_wait>. - Tag VFS deletable in <devfs_mk_symlink> if handle ignored. - v1.10 - 20020129 Richard Gooch <rgooch@atnf.csiro.au> - Added KERN_* to remaining messages. - Cleaned up declaration of <stat_read>. - v1.11 - 20020219 Richard Gooch <rgooch@atnf.csiro.au> - Changed <devfs_rmdir> to allow later additions if not yet empty. - v1.12 - 20020406 Richard Gooch <rgooch@atnf.csiro.au> - Removed silently introduced calls to lock_kernel() and - unlock_kernel() due to recent VFS locking changes. BKL isn't - required in devfs. - v1.13 - 20020428 Richard Gooch <rgooch@atnf.csiro.au> - Removed 2.4.x compatibility code. - v1.14 - 20020510 Richard Gooch <rgooch@atnf.csiro.au> - Added BKL to <devfs_open> because drivers still need it. - v1.15 - 20020512 Richard Gooch <rgooch@atnf.csiro.au> - Protected <scan_dir_for_removable> and <get_removable_partition> - from changing directory contents. - v1.16 - 20020514 Richard Gooch <rgooch@atnf.csiro.au> - Minor cleanup of <scan_dir_for_removable>. - v1.17 - 20020721 Richard Gooch <rgooch@atnf.csiro.au> - Switched to ISO C structure field initialisers. - Switch to set_current_state() and move before add_wait_queue(). - 20020722 Richard Gooch <rgooch@atnf.csiro.au> - Fixed devfs entry leak in <devfs_readdir> when *readdir fails. - v1.18 - 20020725 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_find_and_unregister>. - v1.19 - 20020728 Richard Gooch <rgooch@atnf.csiro.au> - Removed deprecated <devfs_find_handle>. - v1.20 - 20020820 Richard Gooch <rgooch@atnf.csiro.au> - Fixed module unload race in <devfs_open>. - v1.21 - 20021013 Richard Gooch <rgooch@atnf.csiro.au> - Removed DEVFS_ FL_AUTO_OWNER. - Switched lingering structure field initialiser to ISO C. - Added locking when updating FCB flags. - v1.22 -*/ -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/time.h> -#include <linux/tty.h> -#include <linux/timer.h> -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/wait.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/ctype.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/devfs_fs.h> -#include <linux/devfs_fs_kernel.h> -#include <linux/smp_lock.h> -#include <linux/smp.h> -#include <linux/rwsem.h> -#include <linux/sched.h> -#include <linux/namei.h> -#include <linux/bitops.h> - -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/processor.h> -#include <asm/system.h> -#include <asm/pgtable.h> -#include <asm/atomic.h> - -#define DEVFS_VERSION "2004-01-31" - -#define DEVFS_NAME "devfs" - -#define FIRST_INODE 1 - -#define STRING_LENGTH 256 -#define FAKE_BLOCK_SIZE 1024 -#define POISON_PTR ( *(void **) poison_array ) -#define MAGIC_VALUE 0x327db823 - -#ifndef TRUE -# define TRUE 1 -# define FALSE 0 -#endif - -#define MODE_DIR (S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO) - -#define DEBUG_NONE 0x0000000 -#define DEBUG_MODULE_LOAD 0x0000001 -#define DEBUG_REGISTER 0x0000002 -#define DEBUG_UNREGISTER 0x0000004 -#define DEBUG_FREE 0x0000008 -#define DEBUG_SET_FLAGS 0x0000010 -#define DEBUG_S_READ 0x0000100 /* Break */ -#define DEBUG_I_LOOKUP 0x0001000 /* Break */ -#define DEBUG_I_CREATE 0x0002000 -#define DEBUG_I_GET 0x0004000 -#define DEBUG_I_CHANGE 0x0008000 -#define DEBUG_I_UNLINK 0x0010000 -#define DEBUG_I_RLINK 0x0020000 -#define DEBUG_I_FLINK 0x0040000 -#define DEBUG_I_MKNOD 0x0080000 -#define DEBUG_F_READDIR 0x0100000 /* Break */ -#define DEBUG_D_DELETE 0x1000000 /* Break */ -#define DEBUG_D_RELEASE 0x2000000 -#define DEBUG_D_IPUT 0x4000000 -#define DEBUG_ALL 0xfffffff -#define DEBUG_DISABLED DEBUG_NONE - -#define OPTION_NONE 0x00 -#define OPTION_MOUNT 0x01 - -#define PRINTK(format, args...) \ - {printk (KERN_ERR "%s" format, __FUNCTION__ , ## args);} - -#define OOPS(format, args...) \ - {printk (KERN_CRIT "%s" format, __FUNCTION__ , ## args); \ - printk ("Forcing Oops\n"); \ - BUG();} - -#ifdef CONFIG_DEVFS_DEBUG -# define VERIFY_ENTRY(de) \ - {if ((de) && (de)->magic_number != MAGIC_VALUE) \ - OOPS ("(%p): bad magic value: %x\n", (de), (de)->magic_number);} -# define WRITE_ENTRY_MAGIC(de,magic) (de)->magic_number = (magic) -# define DPRINTK(flag, format, args...) \ - {if (devfs_debug & flag) \ - printk (KERN_INFO "%s" format, __FUNCTION__ , ## args);} -#else -# define VERIFY_ENTRY(de) -# define WRITE_ENTRY_MAGIC(de,magic) -# define DPRINTK(flag, format, args...) -#endif - -typedef struct devfs_entry *devfs_handle_t; - -struct directory_type { - rwlock_t lock; /* Lock for searching(R)/updating(W) */ - struct devfs_entry *first; - struct devfs_entry *last; - unsigned char no_more_additions:1; -}; - -struct symlink_type { - unsigned int length; /* Not including the NULL-termimator */ - char *linkname; /* This is NULL-terminated */ -}; - -struct devfs_inode { /* This structure is for "persistent" inode storage */ - struct dentry *dentry; - struct timespec atime; - struct timespec mtime; - struct timespec ctime; - unsigned int ino; /* Inode number as seen in the VFS */ - uid_t uid; - gid_t gid; -}; - -struct devfs_entry { -#ifdef CONFIG_DEVFS_DEBUG - unsigned int magic_number; -#endif - void *info; - atomic_t refcount; /* When this drops to zero, it's unused */ - union { - struct directory_type dir; - dev_t dev; - struct symlink_type symlink; - const char *name; /* Only used for (mode == 0) */ - } u; - struct devfs_entry *prev; /* Previous entry in the parent directory */ - struct devfs_entry *next; /* Next entry in the parent directory */ - struct devfs_entry *parent; /* The parent directory */ - struct devfs_inode inode; - umode_t mode; - unsigned short namelen; /* I think 64k+ filenames are a way off... */ - unsigned char vfs:1; /* Whether the VFS may delete the entry */ - char name[1]; /* This is just a dummy: the allocated array - is bigger. This is NULL-terminated */ -}; - -/* The root of the device tree */ -static struct devfs_entry *root_entry; - -struct devfsd_buf_entry { - struct devfs_entry *de; /* The name is generated with this */ - unsigned short type; /* The type of event */ - umode_t mode; - uid_t uid; - gid_t gid; - struct devfsd_buf_entry *next; -}; - -struct fs_info { /* This structure is for the mounted devfs */ - struct super_block *sb; - spinlock_t devfsd_buffer_lock; /* Lock when inserting/deleting events */ - struct devfsd_buf_entry *devfsd_first_event; - struct devfsd_buf_entry *devfsd_last_event; - volatile int devfsd_sleeping; - volatile struct task_struct *devfsd_task; - volatile pid_t devfsd_pgrp; - volatile struct file *devfsd_file; - struct devfsd_notify_struct *devfsd_info; - volatile unsigned long devfsd_event_mask; - atomic_t devfsd_overrun_count; - wait_queue_head_t devfsd_wait_queue; /* Wake devfsd on input */ - wait_queue_head_t revalidate_wait_queue; /* Wake when devfsd sleeps */ -}; - -static struct fs_info fs_info = {.devfsd_buffer_lock = SPIN_LOCK_UNLOCKED }; -static kmem_cache_t *devfsd_buf_cache; -#ifdef CONFIG_DEVFS_DEBUG -static unsigned int devfs_debug_init __initdata = DEBUG_NONE; -static unsigned int devfs_debug = DEBUG_NONE; -static DEFINE_SPINLOCK(stat_lock); -static unsigned int stat_num_entries; -static unsigned int stat_num_bytes; -#endif -static unsigned char poison_array[8] = - { 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a }; - -#ifdef CONFIG_DEVFS_MOUNT -static unsigned int boot_options = OPTION_MOUNT; -#else -static unsigned int boot_options = OPTION_NONE; -#endif - -/* Forward function declarations */ -static devfs_handle_t _devfs_walk_path(struct devfs_entry *dir, - const char *name, int namelen, - int traverse_symlink); -static ssize_t devfsd_read(struct file *file, char __user *buf, size_t len, - loff_t * ppos); -static int devfsd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -static int devfsd_close(struct inode *inode, struct file *file); -#ifdef CONFIG_DEVFS_DEBUG -static ssize_t stat_read(struct file *file, char __user *buf, size_t len, - loff_t * ppos); -static const struct file_operations stat_fops = { - .open = nonseekable_open, - .read = stat_read, -}; -#endif - -/* Devfs daemon file operations */ -static const struct file_operations devfsd_fops = { - .open = nonseekable_open, - .read = devfsd_read, - .ioctl = devfsd_ioctl, - .release = devfsd_close, -}; - -/* Support functions follow */ - -/** - * devfs_get - Get a reference to a devfs entry. - * @de: The devfs entry. - */ - -static struct devfs_entry *devfs_get(struct devfs_entry *de) -{ - VERIFY_ENTRY(de); - if (de) - atomic_inc(&de->refcount); - return de; -} /* End Function devfs_get */ - -/** - * devfs_put - Put (release) a reference to a devfs entry. - * @de: The handle to the devfs entry. - */ - -static void devfs_put(devfs_handle_t de) -{ - if (!de) - return; - VERIFY_ENTRY(de); - if (de->info == POISON_PTR) - OOPS("(%p): poisoned pointer\n", de); - if (!atomic_dec_and_test(&de->refcount)) - return; - if (de == root_entry) - OOPS("(%p): root entry being freed\n", de); - DPRINTK(DEBUG_FREE, "(%s): de: %p, parent: %p \"%s\"\n", - de->name, de, de->parent, - de->parent ? de->parent->name : "no parent"); - if (S_ISLNK(de->mode)) - kfree(de->u.symlink.linkname); - WRITE_ENTRY_MAGIC(de, 0); -#ifdef CONFIG_DEVFS_DEBUG - spin_lock(&stat_lock); - --stat_num_entries; - stat_num_bytes -= sizeof *de + de->namelen; - if (S_ISLNK(de->mode)) - stat_num_bytes -= de->u.symlink.length + 1; - spin_unlock(&stat_lock); -#endif - de->info = POISON_PTR; - kfree(de); -} /* End Function devfs_put */ - -/** - * _devfs_search_dir - Search for a devfs entry in a directory. - * @dir: The directory to search. - * @name: The name of the entry to search for. - * @namelen: The number of characters in @name. - * - * Search for a devfs entry in a directory and returns a pointer to the entry - * on success, else %NULL. The directory must be locked already. - * An implicit devfs_get() is performed on the returned entry. - */ - -static struct devfs_entry *_devfs_search_dir(struct devfs_entry *dir, - const char *name, - unsigned int namelen) -{ - struct devfs_entry *curr; - - if (!S_ISDIR(dir->mode)) { - PRINTK("(%s): not a directory\n", dir->name); - return NULL; - } - for (curr = dir->u.dir.first; curr != NULL; curr = curr->next) { - if (curr->namelen != namelen) - continue; - if (memcmp(curr->name, name, namelen) == 0) - break; - /* Not found: try the next one */ - } - return devfs_get(curr); -} /* End Function _devfs_search_dir */ - -/** - * _devfs_alloc_entry - Allocate a devfs entry. - * @name: the name of the entry - * @namelen: the number of characters in @name - * @mode: the mode for the entry - * - * Allocate a devfs entry and returns a pointer to the entry on success, else - * %NULL. - */ - -static struct devfs_entry *_devfs_alloc_entry(const char *name, - unsigned int namelen, - umode_t mode) -{ - struct devfs_entry *new; - static unsigned long inode_counter = FIRST_INODE; - static DEFINE_SPINLOCK(counter_lock); - - if (name && (namelen < 1)) - namelen = strlen(name); - if ((new = kmalloc(sizeof *new + namelen, GFP_KERNEL)) == NULL) - return NULL; - memset(new, 0, sizeof *new + namelen); /* Will set '\0' on name */ - new->mode = mode; - if (S_ISDIR(mode)) - rwlock_init(&new->u.dir.lock); - atomic_set(&new->refcount, 1); - spin_lock(&counter_lock); - new->inode.ino = inode_counter++; - spin_unlock(&counter_lock); - if (name) - memcpy(new->name, name, namelen); - new->namelen = namelen; - WRITE_ENTRY_MAGIC(new, MAGIC_VALUE); -#ifdef CONFIG_DEVFS_DEBUG - spin_lock(&stat_lock); - ++stat_num_entries; - stat_num_bytes += sizeof *new + namelen; - spin_unlock(&stat_lock); -#endif - return new; -} /* End Function _devfs_alloc_entry */ - -/** - * _devfs_append_entry - Append a devfs entry to a directory's child list. - * @dir: The directory to add to. - * @de: The devfs entry to append. - * @old_de: If an existing entry exists, it will be written here. This may - * be %NULL. An implicit devfs_get() is performed on this entry. - * - * Append a devfs entry to a directory's list of children, checking first to - * see if an entry of the same name exists. The directory will be locked. - * The value 0 is returned on success, else a negative error code. - * On failure, an implicit devfs_put() is performed on %de. - */ - -static int _devfs_append_entry(devfs_handle_t dir, devfs_handle_t de, - devfs_handle_t * old_de) -{ - int retval; - - if (old_de) - *old_de = NULL; - if (!S_ISDIR(dir->mode)) { - PRINTK("(%s): dir: \"%s\" is not a directory\n", de->name, - dir->name); - devfs_put(de); - return -ENOTDIR; - } - write_lock(&dir->u.dir.lock); - if (dir->u.dir.no_more_additions) - retval = -ENOENT; - else { - struct devfs_entry *old; - - old = _devfs_search_dir(dir, de->name, de->namelen); - if (old_de) - *old_de = old; - else - devfs_put(old); - if (old == NULL) { - de->parent = dir; - de->prev = dir->u.dir.last; - /* Append to the directory's list of children */ - if (dir->u.dir.first == NULL) - dir->u.dir.first = de; - else - dir->u.dir.last->next = de; - dir->u.dir.last = de; - retval = 0; - } else - retval = -EEXIST; - } - write_unlock(&dir->u.dir.lock); - if (retval) - devfs_put(de); - return retval; -} /* End Function _devfs_append_entry */ - -/** - * _devfs_get_root_entry - Get the root devfs entry. - * - * Returns the root devfs entry on success, else %NULL. - * - * TODO it must be called asynchronously due to the fact - * that devfs is initialized relatively late. Proper way - * is to remove module_init from init_devfs_fs and manually - * call it early enough during system init - */ - -static struct devfs_entry *_devfs_get_root_entry(void) -{ - struct devfs_entry *new; - static DEFINE_SPINLOCK(root_lock); - - if (root_entry) - return root_entry; - - new = _devfs_alloc_entry(NULL, 0, MODE_DIR); - if (new == NULL) - return NULL; - - spin_lock(&root_lock); - if (root_entry) { - spin_unlock(&root_lock); - devfs_put(new); - return root_entry; - } - root_entry = new; - spin_unlock(&root_lock); - - return root_entry; -} /* End Function _devfs_get_root_entry */ - -/** - * _devfs_descend - Descend down a tree using the next component name. - * @dir: The directory to search. - * @name: The component name to search for. - * @namelen: The length of %name. - * @next_pos: The position of the next '/' or '\0' is written here. - * - * Descend into a directory, searching for a component. This function forms - * the core of a tree-walking algorithm. The directory will be locked. - * The devfs entry corresponding to the component is returned. If there is - * no matching entry, %NULL is returned. - * An implicit devfs_get() is performed on the returned entry. - */ - -static struct devfs_entry *_devfs_descend(struct devfs_entry *dir, - const char *name, int namelen, - int *next_pos) -{ - const char *stop, *ptr; - struct devfs_entry *entry; - - if ((namelen >= 3) && (strncmp(name, "../", 3) == 0)) { /* Special-case going to parent directory */ - *next_pos = 3; - return devfs_get(dir->parent); - } - stop = name + namelen; - /* Search for a possible '/' */ - for (ptr = name; (ptr < stop) && (*ptr != '/'); ++ptr) ; - *next_pos = ptr - name; - read_lock(&dir->u.dir.lock); - entry = _devfs_search_dir(dir, name, *next_pos); - read_unlock(&dir->u.dir.lock); - return entry; -} /* End Function _devfs_descend */ - -static devfs_handle_t _devfs_make_parent_for_leaf(struct devfs_entry *dir, - const char *name, - int namelen, int *leaf_pos) -{ - int next_pos = 0; - - if (dir == NULL) - dir = _devfs_get_root_entry(); - if (dir == NULL) - return NULL; - devfs_get(dir); - /* Search for possible trailing component and ignore it */ - for (--namelen; (namelen > 0) && (name[namelen] != '/'); --namelen) ; - *leaf_pos = (name[namelen] == '/') ? (namelen + 1) : 0; - for (; namelen > 0; name += next_pos, namelen -= next_pos) { - struct devfs_entry *de, *old = NULL; - - if ((de = - _devfs_descend(dir, name, namelen, &next_pos)) == NULL) { - de = _devfs_alloc_entry(name, next_pos, MODE_DIR); - devfs_get(de); - if (!de || _devfs_append_entry(dir, de, &old)) { - devfs_put(de); - if (!old || !S_ISDIR(old->mode)) { - devfs_put(old); - devfs_put(dir); - return NULL; - } - de = old; /* Use the existing directory */ - } - } - if (de == dir->parent) { - devfs_put(dir); - devfs_put(de); - return NULL; - } - devfs_put(dir); - dir = de; - if (name[next_pos] == '/') - ++next_pos; - } - return dir; -} /* End Function _devfs_make_parent_for_leaf */ - -static devfs_handle_t _devfs_prepare_leaf(devfs_handle_t * dir, - const char *name, umode_t mode) -{ - int namelen, leaf_pos; - struct devfs_entry *de; - - namelen = strlen(name); - if ((*dir = _devfs_make_parent_for_leaf(*dir, name, namelen, - &leaf_pos)) == NULL) { - PRINTK("(%s): could not create parent path\n", name); - return NULL; - } - if ((de = _devfs_alloc_entry(name + leaf_pos, namelen - leaf_pos, mode)) - == NULL) { - PRINTK("(%s): could not allocate entry\n", name); - devfs_put(*dir); - return NULL; - } - return de; -} /* End Function _devfs_prepare_leaf */ - -static devfs_handle_t _devfs_walk_path(struct devfs_entry *dir, - const char *name, int namelen, - int traverse_symlink) -{ - int next_pos = 0; - - if (dir == NULL) - dir = _devfs_get_root_entry(); - if (dir == NULL) - return NULL; - devfs_get(dir); - for (; namelen > 0; name += next_pos, namelen -= next_pos) { - struct devfs_entry *de, *link; - - if (!S_ISDIR(dir->mode)) { - devfs_put(dir); - return NULL; - } - - if ((de = - _devfs_descend(dir, name, namelen, &next_pos)) == NULL) { - devfs_put(dir); - return NULL; - } - if (S_ISLNK(de->mode) && traverse_symlink) { /* Need to follow the link: this is a stack chomper */ - /* FIXME what if it puts outside of mounted tree? */ - link = _devfs_walk_path(dir, de->u.symlink.linkname, - de->u.symlink.length, TRUE); - devfs_put(de); - if (!link) { - devfs_put(dir); - return NULL; - } - de = link; - } - devfs_put(dir); - dir = de; - if (name[next_pos] == '/') - ++next_pos; - } - return dir; -} /* End Function _devfs_walk_path */ - -/** - * _devfs_find_entry - Find a devfs entry. - * @dir: The handle to the parent devfs directory entry. If this is %NULL the - * name is relative to the root of the devfs. - * @name: The name of the entry. This may be %NULL. - * @traverse_symlink: If %TRUE then symbolic links are traversed. - * - * Returns the devfs_entry pointer on success, else %NULL. An implicit - * devfs_get() is performed. - */ - -static struct devfs_entry *_devfs_find_entry(devfs_handle_t dir, - const char *name, - int traverse_symlink) -{ - unsigned int namelen = strlen(name); - - if (name[0] == '/') { - /* Skip leading pathname component */ - if (namelen < 2) { - PRINTK("(%s): too short\n", name); - return NULL; - } - for (++name, --namelen; (*name != '/') && (namelen > 0); - ++name, --namelen) ; - if (namelen < 2) { - PRINTK("(%s): too short\n", name); - return NULL; - } - ++name; - --namelen; - } - return _devfs_walk_path(dir, name, namelen, traverse_symlink); -} /* End Function _devfs_find_entry */ - -static struct devfs_entry *get_devfs_entry_from_vfs_inode(struct inode *inode) -{ - if (inode == NULL) - return NULL; - VERIFY_ENTRY((struct devfs_entry *)inode->u.generic_ip); - return inode->u.generic_ip; -} /* End Function get_devfs_entry_from_vfs_inode */ - -/** - * free_dentry - Free the dentry for a device entry and invalidate inode. - * @de: The entry. - * - * This must only be called after the entry has been unhooked from its - * parent directory. - */ - -static void free_dentry(struct devfs_entry *de) -{ - struct dentry *dentry = de->inode.dentry; - - if (!dentry) - return; - spin_lock(&dcache_lock); - dget_locked(dentry); - spin_unlock(&dcache_lock); - /* Forcefully remove the inode */ - if (dentry->d_inode != NULL) - dentry->d_inode->i_nlink = 0; - d_drop(dentry); - dput(dentry); -} /* End Function free_dentry */ - -/** - * is_devfsd_or_child - Test if the current process is devfsd or one of its children. - * @fs_info: The filesystem information. - * - * Returns %TRUE if devfsd or child, else %FALSE. - */ - -static int is_devfsd_or_child(struct fs_info *fs_info) -{ - struct task_struct *p = current; - - if (p == fs_info->devfsd_task) - return (TRUE); - if (process_group(p) == fs_info->devfsd_pgrp) - return (TRUE); - read_lock(&tasklist_lock); - for (; p != &init_task; p = p->real_parent) { - if (p == fs_info->devfsd_task) { - read_unlock(&tasklist_lock); - return (TRUE); - } - } - read_unlock(&tasklist_lock); - return (FALSE); -} /* End Function is_devfsd_or_child */ - -/** - * devfsd_queue_empty - Test if devfsd has work pending in its event queue. - * @fs_info: The filesystem information. - * - * Returns %TRUE if the queue is empty, else %FALSE. - */ - -static inline int devfsd_queue_empty(struct fs_info *fs_info) -{ - return (fs_info->devfsd_last_event) ? FALSE : TRUE; -} /* End Function devfsd_queue_empty */ - -/** - * wait_for_devfsd_finished - Wait for devfsd to finish processing its event queue. - * @fs_info: The filesystem information. - * - * Returns %TRUE if no more waiting will be required, else %FALSE. - */ - -static int wait_for_devfsd_finished(struct fs_info *fs_info) -{ - DECLARE_WAITQUEUE(wait, current); - - if (fs_info->devfsd_task == NULL) - return (TRUE); - if (devfsd_queue_empty(fs_info) && fs_info->devfsd_sleeping) - return TRUE; - if (is_devfsd_or_child(fs_info)) - return (FALSE); - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&fs_info->revalidate_wait_queue, &wait); - if (!devfsd_queue_empty(fs_info) || !fs_info->devfsd_sleeping) - if (fs_info->devfsd_task) - schedule(); - remove_wait_queue(&fs_info->revalidate_wait_queue, &wait); - __set_current_state(TASK_RUNNING); - return (TRUE); -} /* End Function wait_for_devfsd_finished */ - -/** - * devfsd_notify_de - Notify the devfsd daemon of a change. - * @de: The devfs entry that has changed. This and all parent entries will - * have their reference counts incremented if the event was queued. - * @type: The type of change. - * @mode: The mode of the entry. - * @uid: The user ID. - * @gid: The group ID. - * @fs_info: The filesystem info. - * - * Returns %TRUE if an event was queued and devfsd woken up, else %FALSE. - */ - -static int devfsd_notify_de(struct devfs_entry *de, - unsigned short type, umode_t mode, - uid_t uid, gid_t gid, struct fs_info *fs_info) -{ - struct devfsd_buf_entry *entry; - struct devfs_entry *curr; - - if (!(fs_info->devfsd_event_mask & (1 << type))) - return (FALSE); - if ((entry = kmem_cache_alloc(devfsd_buf_cache, SLAB_KERNEL)) == NULL) { - atomic_inc(&fs_info->devfsd_overrun_count); - return (FALSE); - } - for (curr = de; curr != NULL; curr = curr->parent) - devfs_get(curr); - entry->de = de; - entry->type = type; - entry->mode = mode; - entry->uid = uid; - entry->gid = gid; - entry->next = NULL; - spin_lock(&fs_info->devfsd_buffer_lock); - if (!fs_info->devfsd_first_event) - fs_info->devfsd_first_event = entry; - if (fs_info->devfsd_last_event) - fs_info->devfsd_last_event->next = entry; - fs_info->devfsd_last_event = entry; - spin_unlock(&fs_info->devfsd_buffer_lock); - wake_up_interruptible(&fs_info->devfsd_wait_queue); - return (TRUE); -} /* End Function devfsd_notify_de */ - -/** - * devfsd_notify - Notify the devfsd daemon of a change. - * @de: The devfs entry that has changed. - * @type: The type of change event. - * @wait: If TRUE, the function waits for the daemon to finish processing - * the event. - */ - -static void devfsd_notify(struct devfs_entry *de, unsigned short type) -{ - devfsd_notify_de(de, type, de->mode, current->euid, - current->egid, &fs_info); -} - -static int devfs_mk_dev(dev_t dev, umode_t mode, const char *fmt, va_list args) -{ - struct devfs_entry *dir = NULL, *de; - char buf[64]; - int error, n; - - n = vsnprintf(buf, sizeof(buf), fmt, args); - if (n >= sizeof(buf) || !buf[0]) { - printk(KERN_WARNING "%s: invalid format string %s\n", - __FUNCTION__, fmt); - return -EINVAL; - } - - de = _devfs_prepare_leaf(&dir, buf, mode); - if (!de) { - printk(KERN_WARNING "%s: could not prepare leaf for %s\n", - __FUNCTION__, buf); - return -ENOMEM; /* could be more accurate... */ - } - - de->u.dev = dev; - - error = _devfs_append_entry(dir, de, NULL); - if (error) { - printk(KERN_WARNING "%s: could not append to parent for %s\n", - __FUNCTION__, buf); - goto out; - } - - devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED); - out: - devfs_put(dir); - return error; -} - -int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...) -{ - va_list args; - - if (!S_ISBLK(mode)) { - printk(KERN_WARNING "%s: invalide mode (%u) for %s\n", - __FUNCTION__, mode, fmt); - return -EINVAL; - } - - va_start(args, fmt); - return devfs_mk_dev(dev, mode, fmt, args); -} - -EXPORT_SYMBOL(devfs_mk_bdev); - -int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...) -{ - va_list args; - - if (!S_ISCHR(mode)) { - printk(KERN_WARNING "%s: invalide mode (%u) for %s\n", - __FUNCTION__, mode, fmt); - return -EINVAL; - } - - va_start(args, fmt); - return devfs_mk_dev(dev, mode, fmt, args); -} - -EXPORT_SYMBOL(devfs_mk_cdev); - -/** - * _devfs_unhook - Unhook a device entry from its parents list - * @de: The entry to unhook. - * - * Returns %TRUE if the entry was unhooked, else %FALSE if it was - * previously unhooked. - * The caller must have a write lock on the parent directory. - */ - -static int _devfs_unhook(struct devfs_entry *de) -{ - struct devfs_entry *parent; - - if (!de || (de->prev == de)) - return FALSE; - parent = de->parent; - if (de->prev == NULL) - parent->u.dir.first = de->next; - else - de->prev->next = de->next; - if (de->next == NULL) - parent->u.dir.last = de->prev; - else - de->next->prev = de->prev; - de->prev = de; /* Indicate we're unhooked */ - de->next = NULL; /* Force early termination for <devfs_readdir> */ - return TRUE; -} /* End Function _devfs_unhook */ - -/** - * _devfs_unregister - Unregister a device entry from its parent. - * @dir: The parent directory. - * @de: The entry to unregister. - * - * The caller must have a write lock on the parent directory, which is - * unlocked by this function. - */ - -static void _devfs_unregister(struct devfs_entry *dir, struct devfs_entry *de) -{ - int unhooked = _devfs_unhook(de); - - write_unlock(&dir->u.dir.lock); - if (!unhooked) - return; - devfs_get(dir); - devfsd_notify(de, DEVFSD_NOTIFY_UNREGISTERED); - free_dentry(de); - devfs_put(dir); - if (!S_ISDIR(de->mode)) - return; - while (TRUE) { /* Recursively unregister: this is a stack chomper */ - struct devfs_entry *child; - - write_lock(&de->u.dir.lock); - de->u.dir.no_more_additions = TRUE; - child = de->u.dir.first; - VERIFY_ENTRY(child); - _devfs_unregister(de, child); - if (!child) - break; - DPRINTK(DEBUG_UNREGISTER, "(%s): child: %p refcount: %d\n", - child->name, child, atomic_read(&child->refcount)); - devfs_put(child); - } -} /* End Function _devfs_unregister */ - -static int devfs_do_symlink(devfs_handle_t dir, const char *name, - const char *link, devfs_handle_t * handle) -{ - int err; - unsigned int linklength; - char *newlink; - struct devfs_entry *de; - - if (handle != NULL) - *handle = NULL; - if (name == NULL) { - PRINTK("(): NULL name pointer\n"); - return -EINVAL; - } - if (link == NULL) { - PRINTK("(%s): NULL link pointer\n", name); - return -EINVAL; - } - linklength = strlen(link); - if ((newlink = kmalloc(linklength + 1, GFP_KERNEL)) == NULL) - return -ENOMEM; - memcpy(newlink, link, linklength); - newlink[linklength] = '\0'; - if ((de = _devfs_prepare_leaf(&dir, name, S_IFLNK | S_IRUGO | S_IXUGO)) - == NULL) { - PRINTK("(%s): could not prepare leaf\n", name); - kfree(newlink); - return -ENOTDIR; - } - de->info = NULL; - de->u.symlink.linkname = newlink; - de->u.symlink.length = linklength; - if ((err = _devfs_append_entry(dir, de, NULL)) != 0) { - PRINTK("(%s): could not append to parent, err: %d\n", name, - err); - devfs_put(dir); - return err; - } - devfs_put(dir); -#ifdef CONFIG_DEVFS_DEBUG - spin_lock(&stat_lock); - stat_num_bytes += linklength + 1; - spin_unlock(&stat_lock); -#endif - if (handle != NULL) - *handle = de; - return 0; -} /* End Function devfs_do_symlink */ - -/** - * devfs_mk_symlink Create a symbolic link in the devfs namespace. - * @from: The name of the entry. - * @to: Name of the destination - * - * Returns 0 on success, else a negative error code is returned. - */ - -int devfs_mk_symlink(const char *from, const char *to) -{ - devfs_handle_t de; - int err; - - err = devfs_do_symlink(NULL, from, to, &de); - if (!err) { - de->vfs = TRUE; - devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED); - } - - return err; -} - -/** - * devfs_mk_dir - Create a directory in the devfs namespace. - * new name is relative to the root of the devfs. - * @fmt: The name of the entry. - * - * Use of this function is optional. The devfs_register() function - * will automatically create intermediate directories as needed. This function - * is provided for efficiency reasons, as it provides a handle to a directory. - * On failure %NULL is returned. - */ - -int devfs_mk_dir(const char *fmt, ...) -{ - struct devfs_entry *dir = NULL, *de = NULL, *old; - char buf[64]; - va_list args; - int error, n; - - va_start(args, fmt); - n = vsnprintf(buf, 64, fmt, args); - if (n >= 64 || !buf[0]) { - printk(KERN_WARNING "%s: invalid argument.", __FUNCTION__); - return -EINVAL; - } - - de = _devfs_prepare_leaf(&dir, buf, MODE_DIR); - if (!de) { - PRINTK("(%s): could not prepare leaf\n", buf); - return -EINVAL; - } - - error = _devfs_append_entry(dir, de, &old); - if (error == -EEXIST && S_ISDIR(old->mode)) { - /* - * devfs_mk_dir() of an already-existing directory will - * return success. - */ - error = 0; - goto out_put; - } else if (error) { - PRINTK("(%s): could not append to dir: %p \"%s\"\n", - buf, dir, dir->name); - devfs_put(old); - goto out_put; - } - - devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED); - - out_put: - devfs_put(dir); - return error; -} - -void devfs_remove(const char *fmt, ...) -{ - char buf[64]; - va_list args; - int n; - - va_start(args, fmt); - n = vsnprintf(buf, sizeof(buf), fmt, args); - if (n < sizeof(buf) && buf[0]) { - devfs_handle_t de = _devfs_find_entry(NULL, buf, 0); - - if (!de) { - printk(KERN_ERR "%s: %s not found, cannot remove\n", - __FUNCTION__, buf); - dump_stack(); - return; - } - - write_lock(&de->parent->u.dir.lock); - _devfs_unregister(de->parent, de); - devfs_put(de); - devfs_put(de); - } -} - -/** - * devfs_generate_path - Generate a pathname for an entry, relative to the devfs root. - * @de: The devfs entry. - * @path: The buffer to write the pathname to. The pathname and '\0' - * terminator will be written at the end of the buffer. - * @buflen: The length of the buffer. - * - * Returns the offset in the buffer where the pathname starts on success, - * else a negative error code. - */ - -static int devfs_generate_path(devfs_handle_t de, char *path, int buflen) -{ - int pos; -#define NAMEOF(de) ( (de)->mode ? (de)->name : (de)->u.name ) - - if (de == NULL) - return -EINVAL; - VERIFY_ENTRY(de); - if (de->namelen >= buflen) - return -ENAMETOOLONG; /* Must be first */ - path[buflen - 1] = '\0'; - if (de->parent == NULL) - return buflen - 1; /* Don't prepend root */ - pos = buflen - de->namelen - 1; - memcpy(path + pos, NAMEOF(de), de->namelen); - for (de = de->parent; de->parent != NULL; de = de->parent) { - if (pos - de->namelen - 1 < 0) - return -ENAMETOOLONG; - path[--pos] = '/'; - pos -= de->namelen; - memcpy(path + pos, NAMEOF(de), de->namelen); - } - return pos; -} /* End Function devfs_generate_path */ - -/** - * devfs_setup - Process kernel boot options. - * @str: The boot options after the "devfs=". - */ - -static int __init devfs_setup(char *str) -{ - static struct { - char *name; - unsigned int mask; - unsigned int *opt; - } devfs_options_tab[] __initdata = { -#ifdef CONFIG_DEVFS_DEBUG - { - "dall", DEBUG_ALL, &devfs_debug_init}, { - "dmod", DEBUG_MODULE_LOAD, &devfs_debug_init}, { - "dreg", DEBUG_REGISTER, &devfs_debug_init}, { - "dunreg", DEBUG_UNREGISTER, &devfs_debug_init}, { - "dfree", DEBUG_FREE, &devfs_debug_init}, { - "diget", DEBUG_I_GET, &devfs_debug_init}, { - "dchange", DEBUG_SET_FLAGS, &devfs_debug_init}, { - "dsread", DEBUG_S_READ, &devfs_debug_init}, { - "dichange", DEBUG_I_CHANGE, &devfs_debug_init}, { - "dimknod", DEBUG_I_MKNOD, &devfs_debug_init}, { - "dilookup", DEBUG_I_LOOKUP, &devfs_debug_init}, { - "diunlink", DEBUG_I_UNLINK, &devfs_debug_init}, -#endif /* CONFIG_DEVFS_DEBUG */ - { - "mount", OPTION_MOUNT, &boot_options}, { - NULL, 0, NULL} - }; - - while ((*str != '\0') && !isspace(*str)) { - int i, found = 0, invert = 0; - - if (strncmp(str, "no", 2) == 0) { - invert = 1; - str += 2; - } - for (i = 0; devfs_options_tab[i].name != NULL; i++) { - int len = strlen(devfs_options_tab[i].name); - - if (strncmp(str, devfs_options_tab[i].name, len) == 0) { - if (invert) - *devfs_options_tab[i].opt &= - ~devfs_options_tab[i].mask; - else - *devfs_options_tab[i].opt |= - devfs_options_tab[i].mask; - str += len; - found = 1; - break; - } - } - if (!found) - return 0; /* No match */ - if (*str != ',') - return 0; /* No more options */ - ++str; - } - return 1; -} /* End Function devfs_setup */ - -__setup("devfs=", devfs_setup); - -EXPORT_SYMBOL(devfs_mk_dir); -EXPORT_SYMBOL(devfs_remove); - -/** - * try_modload - Notify devfsd of an inode lookup by a non-devfsd process. - * @parent: The parent devfs entry. - * @fs_info: The filesystem info. - * @name: The device name. - * @namelen: The number of characters in @name. - * @buf: A working area that will be used. This must not go out of scope - * until devfsd is idle again. - * - * Returns 0 on success (event was queued), else a negative error code. - */ - -static int try_modload(struct devfs_entry *parent, struct fs_info *fs_info, - const char *name, unsigned namelen, - struct devfs_entry *buf) -{ - if (!(fs_info->devfsd_event_mask & (1 << DEVFSD_NOTIFY_LOOKUP))) - return -ENOENT; - if (is_devfsd_or_child(fs_info)) - return -ENOENT; - memset(buf, 0, sizeof *buf); - atomic_set(&buf->refcount, 1); - buf->parent = parent; - buf->namelen = namelen; - buf->u.name = name; - WRITE_ENTRY_MAGIC(buf, MAGIC_VALUE); - if (!devfsd_notify_de(buf, DEVFSD_NOTIFY_LOOKUP, 0, - current->euid, current->egid, fs_info)) - return -ENOENT; - /* Possible success: event has been queued */ - return 0; -} /* End Function try_modload */ - -/* Superblock operations follow */ - -static struct inode_operations devfs_iops; -static struct inode_operations devfs_dir_iops; -static const struct file_operations devfs_fops; -static const struct file_operations devfs_dir_fops; -static struct inode_operations devfs_symlink_iops; - -static int devfs_notify_change(struct dentry *dentry, struct iattr *iattr) -{ - int retval; - struct devfs_entry *de; - struct inode *inode = dentry->d_inode; - struct fs_info *fs_info = inode->i_sb->s_fs_info; - - de = get_devfs_entry_from_vfs_inode(inode); - if (de == NULL) - return -ENODEV; - retval = inode_change_ok(inode, iattr); - if (retval != 0) - return retval; - retval = inode_setattr(inode, iattr); - if (retval != 0) - return retval; - DPRINTK(DEBUG_I_CHANGE, "(%d): VFS inode: %p devfs_entry: %p\n", - (int)inode->i_ino, inode, de); - DPRINTK(DEBUG_I_CHANGE, "(): mode: 0%o uid: %d gid: %d\n", - (int)inode->i_mode, (int)inode->i_uid, (int)inode->i_gid); - /* Inode is not on hash chains, thus must save permissions here rather - than in a write_inode() method */ - de->mode = inode->i_mode; - de->inode.uid = inode->i_uid; - de->inode.gid = inode->i_gid; - de->inode.atime = inode->i_atime; - de->inode.mtime = inode->i_mtime; - de->inode.ctime = inode->i_ctime; - if ((iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) && - !is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_CHANGE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - return 0; -} /* End Function devfs_notify_change */ - -static struct super_operations devfs_sops = { - .drop_inode = generic_delete_inode, - .statfs = simple_statfs, -}; - -/** - * _devfs_get_vfs_inode - Get a VFS inode. - * @sb: The super block. - * @de: The devfs inode. - * @dentry: The dentry to register with the devfs inode. - * - * Returns the inode on success, else %NULL. An implicit devfs_get() is - * performed if the inode is created. - */ - -static struct inode *_devfs_get_vfs_inode(struct super_block *sb, - struct devfs_entry *de, - struct dentry *dentry) -{ - struct inode *inode; - - if (de->prev == de) - return NULL; /* Quick check to see if unhooked */ - if ((inode = new_inode(sb)) == NULL) { - PRINTK("(%s): new_inode() failed, de: %p\n", de->name, de); - return NULL; - } - if (de->parent) { - read_lock(&de->parent->u.dir.lock); - if (de->prev != de) - de->inode.dentry = dentry; /* Not unhooked */ - read_unlock(&de->parent->u.dir.lock); - } else - de->inode.dentry = dentry; /* Root: no locking needed */ - if (de->inode.dentry != dentry) { /* Must have been unhooked */ - iput(inode); - return NULL; - } - /* FIXME where is devfs_put? */ - inode->u.generic_ip = devfs_get(de); - inode->i_ino = de->inode.ino; - DPRINTK(DEBUG_I_GET, "(%d): VFS inode: %p devfs_entry: %p\n", - (int)inode->i_ino, inode, de); - inode->i_blocks = 0; - inode->i_blksize = FAKE_BLOCK_SIZE; - inode->i_op = &devfs_iops; - inode->i_mode = de->mode; - if (S_ISDIR(de->mode)) { - inode->i_op = &devfs_dir_iops; - inode->i_fop = &devfs_dir_fops; - } else if (S_ISLNK(de->mode)) { - inode->i_op = &devfs_symlink_iops; - inode->i_size = de->u.symlink.length; - } else if (S_ISCHR(de->mode) || S_ISBLK(de->mode)) { - init_special_inode(inode, de->mode, de->u.dev); - } else if (S_ISFIFO(de->mode) || S_ISSOCK(de->mode)) { - init_special_inode(inode, de->mode, 0); - } else { - PRINTK("(%s): unknown mode %o de: %p\n", - de->name, de->mode, de); - iput(inode); - devfs_put(de); - return NULL; - } - - inode->i_uid = de->inode.uid; - inode->i_gid = de->inode.gid; - inode->i_atime = de->inode.atime; - inode->i_mtime = de->inode.mtime; - inode->i_ctime = de->inode.ctime; - DPRINTK(DEBUG_I_GET, "(): mode: 0%o uid: %d gid: %d\n", - (int)inode->i_mode, (int)inode->i_uid, (int)inode->i_gid); - return inode; -} /* End Function _devfs_get_vfs_inode */ - -/* File operations for device entries follow */ - -static int devfs_readdir(struct file *file, void *dirent, filldir_t filldir) -{ - int err, count; - int stored = 0; - struct fs_info *fs_info; - struct devfs_entry *parent, *de, *next = NULL; - struct inode *inode = file->f_dentry->d_inode; - - fs_info = inode->i_sb->s_fs_info; - parent = get_devfs_entry_from_vfs_inode(file->f_dentry->d_inode); - if ((long)file->f_pos < 0) - return -EINVAL; - DPRINTK(DEBUG_F_READDIR, "(%s): fs_info: %p pos: %ld\n", - parent->name, fs_info, (long)file->f_pos); - switch ((long)file->f_pos) { - case 0: - err = (*filldir) (dirent, "..", 2, file->f_pos, - parent_ino(file->f_dentry), DT_DIR); - if (err == -EINVAL) - break; - if (err < 0) - return err; - file->f_pos++; - ++stored; - /* Fall through */ - case 1: - err = - (*filldir) (dirent, ".", 1, file->f_pos, inode->i_ino, - DT_DIR); - if (err == -EINVAL) - break; - if (err < 0) - return err; - file->f_pos++; - ++stored; - /* Fall through */ - default: - /* Skip entries */ - count = file->f_pos - 2; - read_lock(&parent->u.dir.lock); - for (de = parent->u.dir.first; de && (count > 0); de = de->next) - --count; - devfs_get(de); - read_unlock(&parent->u.dir.lock); - /* Now add all remaining entries */ - while (de) { - err = (*filldir) (dirent, de->name, de->namelen, - file->f_pos, de->inode.ino, - de->mode >> 12); - if (err < 0) - devfs_put(de); - else { - file->f_pos++; - ++stored; - } - if (err == -EINVAL) - break; - if (err < 0) - return err; - read_lock(&parent->u.dir.lock); - next = devfs_get(de->next); - read_unlock(&parent->u.dir.lock); - devfs_put(de); - de = next; - } - break; - } - return stored; -} /* End Function devfs_readdir */ - -/* Open devfs specific special files */ -static int devfs_open(struct inode *inode, struct file *file) -{ - int err; - int minor = MINOR(inode->i_rdev); - struct file_operations *old_fops, *new_fops; - - switch (minor) { - case 0: /* /dev/.devfsd */ - new_fops = fops_get(&devfsd_fops); - break; -#ifdef CONFIG_DEVFS_DEBUG - case 1: /* /dev/.stat */ - new_fops = fops_get(&stat_fops); - break; -#endif - default: - return -ENODEV; - } - - if (new_fops == NULL) - return -ENODEV; - old_fops = file->f_op; - file->f_op = new_fops; - err = new_fops->open ? new_fops->open(inode, file) : 0; - if (err) { - file->f_op = old_fops; - fops_put(new_fops); - } else - fops_put(old_fops); - return err; -} /* End Function devfs_open */ - -static const struct file_operations devfs_fops = { - .open = devfs_open, -}; - -static const struct file_operations devfs_dir_fops = { - .read = generic_read_dir, - .readdir = devfs_readdir, -}; - -/* Dentry operations for device entries follow */ - -/** - * devfs_d_release - Callback for when a dentry is freed. - * @dentry: The dentry. - */ - -static void devfs_d_release(struct dentry *dentry) -{ - DPRINTK(DEBUG_D_RELEASE, "(%p): inode: %p\n", dentry, dentry->d_inode); -} /* End Function devfs_d_release */ - -/** - * devfs_d_iput - Callback for when a dentry loses its inode. - * @dentry: The dentry. - * @inode: The inode. - */ - -static void devfs_d_iput(struct dentry *dentry, struct inode *inode) -{ - struct devfs_entry *de; - - de = get_devfs_entry_from_vfs_inode(inode); - DPRINTK(DEBUG_D_IPUT, - "(%s): dentry: %p inode: %p de: %p de->dentry: %p\n", de->name, - dentry, inode, de, de->inode.dentry); - if (de->inode.dentry && (de->inode.dentry != dentry)) - OOPS("(%s): de: %p dentry: %p de->dentry: %p\n", - de->name, de, dentry, de->inode.dentry); - de->inode.dentry = NULL; - iput(inode); - devfs_put(de); -} /* End Function devfs_d_iput */ - -static int devfs_d_delete(struct dentry *dentry); - -static struct dentry_operations devfs_dops = { - .d_delete = devfs_d_delete, - .d_release = devfs_d_release, - .d_iput = devfs_d_iput, -}; - -static int devfs_d_revalidate_wait(struct dentry *dentry, struct nameidata *); - -static struct dentry_operations devfs_wait_dops = { - .d_delete = devfs_d_delete, - .d_release = devfs_d_release, - .d_iput = devfs_d_iput, - .d_revalidate = devfs_d_revalidate_wait, -}; - -/** - * devfs_d_delete - Callback for when all files for a dentry are closed. - * @dentry: The dentry. - */ - -static int devfs_d_delete(struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - - if (dentry->d_op == &devfs_wait_dops) - dentry->d_op = &devfs_dops; - /* Unhash dentry if negative (has no inode) */ - if (inode == NULL) { - DPRINTK(DEBUG_D_DELETE, "(%p): dropping negative dentry\n", - dentry); - return 1; - } - return 0; -} /* End Function devfs_d_delete */ - -struct devfs_lookup_struct { - devfs_handle_t de; - wait_queue_head_t wait_queue; -}; - -/* XXX: this doesn't handle the case where we got a negative dentry - but a devfs entry has been registered in the meanwhile */ -static int devfs_d_revalidate_wait(struct dentry *dentry, struct nameidata *nd) -{ - struct inode *dir = dentry->d_parent->d_inode; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - devfs_handle_t parent = get_devfs_entry_from_vfs_inode(dir); - struct devfs_lookup_struct *lookup_info = dentry->d_fsdata; - DECLARE_WAITQUEUE(wait, current); - int need_lock; - - /* - * FIXME HACK - * - * make sure that - * d_instantiate always runs under lock - * we release i_mutex lock before going to sleep - * - * unfortunately sometimes d_revalidate is called with - * and sometimes without i_mutex lock held. The following checks - * attempt to deduce when we need to add (and drop resp.) lock - * here. This relies on current (2.6.2) calling coventions: - * - * lookup_hash is always run under i_mutex and is passing NULL - * as nd - * - * open(...,O_CREATE,...) calls _lookup_hash under i_mutex - * and sets flags to LOOKUP_OPEN|LOOKUP_CREATE - * - * all other invocations of ->d_revalidate seem to happen - * outside of i_mutex - */ - need_lock = nd && - (!(nd->flags & LOOKUP_CREATE) || (nd->flags & LOOKUP_PARENT)); - - if (need_lock) - mutex_lock(&dir->i_mutex); - - if (is_devfsd_or_child(fs_info)) { - devfs_handle_t de = lookup_info->de; - struct inode *inode; - - DPRINTK(DEBUG_I_LOOKUP, - "(%s): dentry: %p inode: %p de: %p by: \"%s\"\n", - dentry->d_name.name, dentry, dentry->d_inode, de, - current->comm); - if (dentry->d_inode) - goto out; - if (de == NULL) { - read_lock(&parent->u.dir.lock); - de = _devfs_search_dir(parent, dentry->d_name.name, - dentry->d_name.len); - read_unlock(&parent->u.dir.lock); - if (de == NULL) - goto out; - lookup_info->de = de; - } - /* Create an inode, now that the driver information is available */ - inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry); - if (!inode) - goto out; - DPRINTK(DEBUG_I_LOOKUP, - "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n", - de->name, de->inode.ino, inode, de, current->comm); - d_instantiate(dentry, inode); - goto out; - } - if (lookup_info == NULL) - goto out; /* Early termination */ - read_lock(&parent->u.dir.lock); - if (dentry->d_fsdata) { - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&lookup_info->wait_queue, &wait); - read_unlock(&parent->u.dir.lock); - /* at this point it is always (hopefully) locked */ - mutex_unlock(&dir->i_mutex); - schedule(); - mutex_lock(&dir->i_mutex); - /* - * This does not need nor should remove wait from wait_queue. - * Wait queue head is never reused - nothing is ever added to it - * after all waiters have been waked up and head itself disappears - * very soon after it. Moreover it is local variable on stack that - * is likely to have already disappeared so any reference to it - * at this point is buggy. - */ - - } else - read_unlock(&parent->u.dir.lock); - - out: - if (need_lock) - mutex_unlock(&dir->i_mutex); - return 1; -} /* End Function devfs_d_revalidate_wait */ - -/* Inode operations for device entries follow */ - -static struct dentry *devfs_lookup(struct inode *dir, struct dentry *dentry, - struct nameidata *nd) -{ - struct devfs_entry tmp; /* Must stay in scope until devfsd idle again */ - struct devfs_lookup_struct lookup_info; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct devfs_entry *parent, *de; - struct inode *inode; - struct dentry *retval = NULL; - - /* Set up the dentry operations before anything else, to ensure cleaning - up on any error */ - dentry->d_op = &devfs_dops; - /* First try to get the devfs entry for this directory */ - parent = get_devfs_entry_from_vfs_inode(dir); - DPRINTK(DEBUG_I_LOOKUP, "(%s): dentry: %p parent: %p by: \"%s\"\n", - dentry->d_name.name, dentry, parent, current->comm); - if (parent == NULL) - return ERR_PTR(-ENOENT); - read_lock(&parent->u.dir.lock); - de = _devfs_search_dir(parent, dentry->d_name.name, dentry->d_name.len); - read_unlock(&parent->u.dir.lock); - lookup_info.de = de; - init_waitqueue_head(&lookup_info.wait_queue); - dentry->d_fsdata = &lookup_info; - if (de == NULL) { /* Try with devfsd. For any kind of failure, leave a negative dentry - so someone else can deal with it (in the case where the sysadmin - does a mknod()). It's important to do this before hashing the - dentry, so that the devfsd queue is filled before revalidates - can start */ - if (try_modload(parent, fs_info, dentry->d_name.name, dentry->d_name.len, &tmp) < 0) { /* Lookup event was not queued to devfsd */ - d_add(dentry, NULL); - return NULL; - } - } - dentry->d_op = &devfs_wait_dops; - d_add(dentry, NULL); /* Open the floodgates */ - /* Unlock directory semaphore, which will release any waiters. They - will get the hashed dentry, and may be forced to wait for - revalidation */ - mutex_unlock(&dir->i_mutex); - wait_for_devfsd_finished(fs_info); /* If I'm not devfsd, must wait */ - mutex_lock(&dir->i_mutex); /* Grab it again because them's the rules */ - de = lookup_info.de; - /* If someone else has been so kind as to make the inode, we go home - early */ - if (dentry->d_inode) - goto out; - if (de == NULL) { - read_lock(&parent->u.dir.lock); - de = _devfs_search_dir(parent, dentry->d_name.name, - dentry->d_name.len); - read_unlock(&parent->u.dir.lock); - if (de == NULL) - goto out; - /* OK, there's an entry now, but no VFS inode yet */ - } - /* Create an inode, now that the driver information is available */ - inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry); - if (!inode) { - retval = ERR_PTR(-ENOMEM); - goto out; - } - DPRINTK(DEBUG_I_LOOKUP, - "(%s): new VFS inode(%u): %p de: %p by: \"%s\"\n", de->name, - de->inode.ino, inode, de, current->comm); - d_instantiate(dentry, inode); - out: - write_lock(&parent->u.dir.lock); - dentry->d_op = &devfs_dops; - dentry->d_fsdata = NULL; - wake_up(&lookup_info.wait_queue); - write_unlock(&parent->u.dir.lock); - devfs_put(de); - return retval; -} /* End Function devfs_lookup */ - -static int devfs_unlink(struct inode *dir, struct dentry *dentry) -{ - int unhooked; - struct devfs_entry *de; - struct inode *inode = dentry->d_inode; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - - de = get_devfs_entry_from_vfs_inode(inode); - DPRINTK(DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de); - if (de == NULL) - return -ENOENT; - if (!de->vfs) - return -EPERM; - write_lock(&de->parent->u.dir.lock); - unhooked = _devfs_unhook(de); - write_unlock(&de->parent->u.dir.lock); - if (!unhooked) - return -ENOENT; - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_DELETE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - free_dentry(de); - devfs_put(de); - return 0; -} /* End Function devfs_unlink */ - -static int devfs_symlink(struct inode *dir, struct dentry *dentry, - const char *symname) -{ - int err; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct devfs_entry *parent, *de; - struct inode *inode; - - /* First try to get the devfs entry for this directory */ - parent = get_devfs_entry_from_vfs_inode(dir); - if (parent == NULL) - return -ENOENT; - err = devfs_do_symlink(parent, dentry->d_name.name, symname, &de); - DPRINTK(DEBUG_DISABLED, "(%s): errcode from <devfs_do_symlink>: %d\n", - dentry->d_name.name, err); - if (err < 0) - return err; - de->vfs = TRUE; - de->inode.uid = current->euid; - de->inode.gid = current->egid; - de->inode.atime = CURRENT_TIME; - de->inode.mtime = CURRENT_TIME; - de->inode.ctime = CURRENT_TIME; - if ((inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry)) == NULL) - return -ENOMEM; - DPRINTK(DEBUG_DISABLED, "(%s): new VFS inode(%u): %p dentry: %p\n", - dentry->d_name.name, de->inode.ino, inode, dentry); - d_instantiate(dentry, inode); - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - return 0; -} /* End Function devfs_symlink */ - -static int devfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) -{ - int err; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct devfs_entry *parent, *de; - struct inode *inode; - - mode = (mode & ~S_IFMT) | S_IFDIR; /* VFS doesn't pass S_IFMT part */ - parent = get_devfs_entry_from_vfs_inode(dir); - if (parent == NULL) - return -ENOENT; - de = _devfs_alloc_entry(dentry->d_name.name, dentry->d_name.len, mode); - if (!de) - return -ENOMEM; - de->vfs = TRUE; - if ((err = _devfs_append_entry(parent, de, NULL)) != 0) - return err; - de->inode.uid = current->euid; - de->inode.gid = current->egid; - de->inode.atime = CURRENT_TIME; - de->inode.mtime = CURRENT_TIME; - de->inode.ctime = CURRENT_TIME; - if ((inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry)) == NULL) - return -ENOMEM; - DPRINTK(DEBUG_DISABLED, "(%s): new VFS inode(%u): %p dentry: %p\n", - dentry->d_name.name, de->inode.ino, inode, dentry); - d_instantiate(dentry, inode); - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - return 0; -} /* End Function devfs_mkdir */ - -static int devfs_rmdir(struct inode *dir, struct dentry *dentry) -{ - int err = 0; - struct devfs_entry *de; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct inode *inode = dentry->d_inode; - - if (dir->i_sb->s_fs_info != inode->i_sb->s_fs_info) - return -EINVAL; - de = get_devfs_entry_from_vfs_inode(inode); - if (de == NULL) - return -ENOENT; - if (!S_ISDIR(de->mode)) - return -ENOTDIR; - if (!de->vfs) - return -EPERM; - /* First ensure the directory is empty and will stay that way */ - write_lock(&de->u.dir.lock); - if (de->u.dir.first) - err = -ENOTEMPTY; - else - de->u.dir.no_more_additions = TRUE; - write_unlock(&de->u.dir.lock); - if (err) - return err; - /* Now unhook the directory from its parent */ - write_lock(&de->parent->u.dir.lock); - if (!_devfs_unhook(de)) - err = -ENOENT; - write_unlock(&de->parent->u.dir.lock); - if (err) - return err; - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_DELETE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - free_dentry(de); - devfs_put(de); - return 0; -} /* End Function devfs_rmdir */ - -static int devfs_mknod(struct inode *dir, struct dentry *dentry, int mode, - dev_t rdev) -{ - int err; - struct fs_info *fs_info = dir->i_sb->s_fs_info; - struct devfs_entry *parent, *de; - struct inode *inode; - - DPRINTK(DEBUG_I_MKNOD, "(%s): mode: 0%o dev: %u:%u\n", - dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); - parent = get_devfs_entry_from_vfs_inode(dir); - if (parent == NULL) - return -ENOENT; - de = _devfs_alloc_entry(dentry->d_name.name, dentry->d_name.len, mode); - if (!de) - return -ENOMEM; - de->vfs = TRUE; - if (S_ISCHR(mode) || S_ISBLK(mode)) - de->u.dev = rdev; - if ((err = _devfs_append_entry(parent, de, NULL)) != 0) - return err; - de->inode.uid = current->euid; - de->inode.gid = current->egid; - de->inode.atime = CURRENT_TIME; - de->inode.mtime = CURRENT_TIME; - de->inode.ctime = CURRENT_TIME; - if ((inode = _devfs_get_vfs_inode(dir->i_sb, de, dentry)) == NULL) - return -ENOMEM; - DPRINTK(DEBUG_I_MKNOD, ": new VFS inode(%u): %p dentry: %p\n", - de->inode.ino, inode, dentry); - d_instantiate(dentry, inode); - if (!is_devfsd_or_child(fs_info)) - devfsd_notify_de(de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); - return 0; -} /* End Function devfs_mknod */ - -static void *devfs_follow_link(struct dentry *dentry, struct nameidata *nd) -{ - struct devfs_entry *p = get_devfs_entry_from_vfs_inode(dentry->d_inode); - nd_set_link(nd, p ? p->u.symlink.linkname : ERR_PTR(-ENODEV)); - return NULL; -} /* End Function devfs_follow_link */ - -static struct inode_operations devfs_iops = { - .setattr = devfs_notify_change, -}; - -static struct inode_operations devfs_dir_iops = { - .lookup = devfs_lookup, - .unlink = devfs_unlink, - .symlink = devfs_symlink, - .mkdir = devfs_mkdir, - .rmdir = devfs_rmdir, - .mknod = devfs_mknod, - .setattr = devfs_notify_change, -}; - -static struct inode_operations devfs_symlink_iops = { - .readlink = generic_readlink, - .follow_link = devfs_follow_link, - .setattr = devfs_notify_change, -}; - -static int devfs_fill_super(struct super_block *sb, void *data, int silent) -{ - struct inode *root_inode = NULL; - - if (_devfs_get_root_entry() == NULL) - goto out_no_root; - atomic_set(&fs_info.devfsd_overrun_count, 0); - init_waitqueue_head(&fs_info.devfsd_wait_queue); - init_waitqueue_head(&fs_info.revalidate_wait_queue); - fs_info.sb = sb; - sb->s_fs_info = &fs_info; - sb->s_blocksize = 1024; - sb->s_blocksize_bits = 10; - sb->s_magic = DEVFS_SUPER_MAGIC; - sb->s_op = &devfs_sops; - sb->s_time_gran = 1; - if ((root_inode = _devfs_get_vfs_inode(sb, root_entry, NULL)) == NULL) - goto out_no_root; - sb->s_root = d_alloc_root(root_inode); - if (!sb->s_root) - goto out_no_root; - DPRINTK(DEBUG_S_READ, "(): made devfs ptr: %p\n", sb->s_fs_info); - return 0; - - out_no_root: - PRINTK("(): get root inode failed\n"); - if (root_inode) - iput(root_inode); - return -EINVAL; -} /* End Function devfs_fill_super */ - -static int devfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data, struct vfsmount *mnt) -{ - return get_sb_single(fs_type, flags, data, devfs_fill_super, mnt); -} - -static struct file_system_type devfs_fs_type = { - .name = DEVFS_NAME, - .get_sb = devfs_get_sb, - .kill_sb = kill_anon_super, -}; - -/* File operations for devfsd follow */ - -static ssize_t devfsd_read(struct file *file, char __user *buf, size_t len, - loff_t * ppos) -{ - int done = FALSE; - int ival; - loff_t pos, devname_offset, tlen, rpos; - devfs_handle_t de; - struct devfsd_buf_entry *entry; - struct fs_info *fs_info = file->f_dentry->d_inode->i_sb->s_fs_info; - struct devfsd_notify_struct *info = fs_info->devfsd_info; - DECLARE_WAITQUEUE(wait, current); - - /* Verify the task has grabbed the queue */ - if (fs_info->devfsd_task != current) - return -EPERM; - info->major = 0; - info->minor = 0; - /* Block for a new entry */ - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&fs_info->devfsd_wait_queue, &wait); - while (devfsd_queue_empty(fs_info)) { - fs_info->devfsd_sleeping = TRUE; - wake_up(&fs_info->revalidate_wait_queue); - schedule(); - fs_info->devfsd_sleeping = FALSE; - if (signal_pending(current)) { - remove_wait_queue(&fs_info->devfsd_wait_queue, &wait); - __set_current_state(TASK_RUNNING); - return -EINTR; - } - set_current_state(TASK_INTERRUPTIBLE); - } - remove_wait_queue(&fs_info->devfsd_wait_queue, &wait); - __set_current_state(TASK_RUNNING); - /* Now play with the data */ - ival = atomic_read(&fs_info->devfsd_overrun_count); - info->overrun_count = ival; - entry = fs_info->devfsd_first_event; - info->type = entry->type; - info->mode = entry->mode; - info->uid = entry->uid; - info->gid = entry->gid; - de = entry->de; - if (S_ISCHR(de->mode) || S_ISBLK(de->mode)) { - info->major = MAJOR(de->u.dev); - info->minor = MINOR(de->u.dev); - } - pos = devfs_generate_path(de, info->devname, DEVFS_PATHLEN); - if (pos < 0) - return pos; - info->namelen = DEVFS_PATHLEN - pos - 1; - if (info->mode == 0) - info->mode = de->mode; - devname_offset = info->devname - (char *)info; - rpos = *ppos; - if (rpos < devname_offset) { - /* Copy parts of the header */ - tlen = devname_offset - rpos; - if (tlen > len) - tlen = len; - if (copy_to_user(buf, (char *)info + rpos, tlen)) { - return -EFAULT; - } - rpos += tlen; - buf += tlen; - len -= tlen; - } - if ((rpos >= devname_offset) && (len > 0)) { - /* Copy the name */ - tlen = info->namelen + 1; - if (tlen > len) - tlen = len; - else - done = TRUE; - if (copy_to_user - (buf, info->devname + pos + rpos - devname_offset, tlen)) { - return -EFAULT; - } - rpos += tlen; - } - tlen = rpos - *ppos; - if (done) { - devfs_handle_t parent; - - spin_lock(&fs_info->devfsd_buffer_lock); - fs_info->devfsd_first_event = entry->next; - if (entry->next == NULL) - fs_info->devfsd_last_event = NULL; - spin_unlock(&fs_info->devfsd_buffer_lock); - for (; de != NULL; de = parent) { - parent = de->parent; - devfs_put(de); - } - kmem_cache_free(devfsd_buf_cache, entry); - if (ival > 0) - atomic_sub(ival, &fs_info->devfsd_overrun_count); - *ppos = 0; - } else - *ppos = rpos; - return tlen; -} /* End Function devfsd_read */ - -static int devfsd_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int ival; - struct fs_info *fs_info = inode->i_sb->s_fs_info; - - switch (cmd) { - case DEVFSDIOC_GET_PROTO_REV: - ival = DEVFSD_PROTOCOL_REVISION_KERNEL; - if (copy_to_user((void __user *)arg, &ival, sizeof ival)) - return -EFAULT; - break; - case DEVFSDIOC_SET_EVENT_MASK: - /* Ensure only one reader has access to the queue. This scheme will - work even if the global kernel lock were to be removed, because it - doesn't matter who gets in first, as long as only one gets it */ - if (fs_info->devfsd_task == NULL) { - static DEFINE_SPINLOCK(lock); - - if (!spin_trylock(&lock)) - return -EBUSY; - if (fs_info->devfsd_task != NULL) { /* We lost the race... */ - spin_unlock(&lock); - return -EBUSY; - } - fs_info->devfsd_task = current; - spin_unlock(&lock); - fs_info->devfsd_pgrp = - (process_group(current) == - current->pid) ? process_group(current) : 0; - fs_info->devfsd_file = file; - fs_info->devfsd_info = - kmalloc(sizeof *fs_info->devfsd_info, GFP_KERNEL); - if (!fs_info->devfsd_info) { - devfsd_close(inode, file); - return -ENOMEM; - } - } else if (fs_info->devfsd_task != current) - return -EBUSY; - fs_info->devfsd_event_mask = arg; /* Let the masses come forth */ - break; - case DEVFSDIOC_RELEASE_EVENT_QUEUE: - if (fs_info->devfsd_file != file) - return -EPERM; - return devfsd_close(inode, file); - /*break; */ -#ifdef CONFIG_DEVFS_DEBUG - case DEVFSDIOC_SET_DEBUG_MASK: - if (copy_from_user(&ival, (void __user *)arg, sizeof ival)) - return -EFAULT; - devfs_debug = ival; - break; -#endif - default: - return -ENOIOCTLCMD; - } - return 0; -} /* End Function devfsd_ioctl */ - -static int devfsd_close(struct inode *inode, struct file *file) -{ - struct devfsd_buf_entry *entry, *next; - struct fs_info *fs_info = inode->i_sb->s_fs_info; - - if (fs_info->devfsd_file != file) - return 0; - fs_info->devfsd_event_mask = 0; - fs_info->devfsd_file = NULL; - spin_lock(&fs_info->devfsd_buffer_lock); - entry = fs_info->devfsd_first_event; - fs_info->devfsd_first_event = NULL; - fs_info->devfsd_last_event = NULL; - kfree(fs_info->devfsd_info); - fs_info->devfsd_info = NULL; - spin_unlock(&fs_info->devfsd_buffer_lock); - fs_info->devfsd_pgrp = 0; - fs_info->devfsd_task = NULL; - wake_up(&fs_info->revalidate_wait_queue); - for (; entry; entry = next) { - next = entry->next; - kmem_cache_free(devfsd_buf_cache, entry); - } - return 0; -} /* End Function devfsd_close */ - -#ifdef CONFIG_DEVFS_DEBUG -static ssize_t stat_read(struct file *file, char __user *buf, size_t len, - loff_t * ppos) -{ - ssize_t num; - char txt[80]; - - num = sprintf(txt, "Number of entries: %u number of bytes: %u\n", - stat_num_entries, stat_num_bytes) + 1; - if (*ppos >= num) - return 0; - if (*ppos + len > num) - len = num - *ppos; - if (copy_to_user(buf, txt + *ppos, len)) - return -EFAULT; - *ppos += len; - return len; -} /* End Function stat_read */ -#endif - -static int __init init_devfs_fs(void) -{ - int err; - int major; - struct devfs_entry *devfsd; -#ifdef CONFIG_DEVFS_DEBUG - struct devfs_entry *stat; -#endif - - if (_devfs_get_root_entry() == NULL) - return -ENOMEM; - - printk(KERN_INFO "%s: %s Richard Gooch (rgooch@atnf.csiro.au)\n", - DEVFS_NAME, DEVFS_VERSION); - devfsd_buf_cache = kmem_cache_create("devfsd_event", - sizeof(struct devfsd_buf_entry), - 0, 0, NULL, NULL); - if (!devfsd_buf_cache) - OOPS("(): unable to allocate event slab\n"); -#ifdef CONFIG_DEVFS_DEBUG - devfs_debug = devfs_debug_init; - printk(KERN_INFO "%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug); -#endif - printk(KERN_INFO "%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options); - - /* register special device for devfsd communication */ - major = register_chrdev(0, "devfs", &devfs_fops); - if (major < 0) - return major; - - /* And create the entry for ".devfsd" */ - devfsd = _devfs_alloc_entry(".devfsd", 0, S_IFCHR | S_IRUSR | S_IWUSR); - if (devfsd == NULL) - return -ENOMEM; - devfsd->u.dev = MKDEV(major, 0); - _devfs_append_entry(root_entry, devfsd, NULL); - -#ifdef CONFIG_DEVFS_DEBUG - stat = _devfs_alloc_entry(".stat", 0, S_IFCHR | S_IRUGO); - if (stat == NULL) - return -ENOMEM; - stat->u.dev = MKDEV(major, 1); - _devfs_append_entry(root_entry, stat, NULL); -#endif - - err = register_filesystem(&devfs_fs_type); - return err; -} /* End Function init_devfs_fs */ - -void __init mount_devfs_fs(void) -{ - int err; - - if (!(boot_options & OPTION_MOUNT)) - return; - err = do_mount("none", "/dev", "devfs", 0, NULL); - if (err == 0) - printk(KERN_INFO "Mounted devfs on /dev\n"); - else - PRINTK("(): unable to mount devfs, err: %d\n", err); -} /* End Function mount_devfs_fs */ - -module_init(init_devfs_fs) diff --git a/fs/devfs/util.c b/fs/devfs/util.c deleted file mode 100644 index db06d388c9a..00000000000 --- a/fs/devfs/util.c +++ /dev/null @@ -1,97 +0,0 @@ -/* devfs (Device FileSystem) utilities. - - Copyright (C) 1999-2002 Richard Gooch - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Richard Gooch may be reached by email at rgooch@atnf.csiro.au - The postal address is: - Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. - - ChangeLog - - 19991031 Richard Gooch <rgooch@atnf.csiro.au> - Created. - 19991103 Richard Gooch <rgooch@atnf.csiro.au> - Created <_devfs_convert_name> and supported SCSI and IDE CD-ROMs - 20000203 Richard Gooch <rgooch@atnf.csiro.au> - Changed operations pointer type to void *. - 20000621 Richard Gooch <rgooch@atnf.csiro.au> - Changed interface to <devfs_register_series>. - 20000622 Richard Gooch <rgooch@atnf.csiro.au> - Took account of interface change to <devfs_mk_symlink>. - Took account of interface change to <devfs_mk_dir>. - 20010519 Richard Gooch <rgooch@atnf.csiro.au> - Documentation cleanup. - 20010709 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_*alloc_major> and <devfs_*alloc_devnum>. - 20010710 Richard Gooch <rgooch@atnf.csiro.au> - Created <devfs_*alloc_unique_number>. - 20010730 Richard Gooch <rgooch@atnf.csiro.au> - Documentation typo fix. - 20010806 Richard Gooch <rgooch@atnf.csiro.au> - Made <block_semaphore> and <char_semaphore> private. - 20010813 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bug in <devfs_alloc_unique_number>: limited to 128 numbers - 20010818 Richard Gooch <rgooch@atnf.csiro.au> - Updated major masks up to Linus' "no new majors" proclamation. - Block: were 126 now 122 free, char: were 26 now 19 free. - 20020324 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bug in <devfs_alloc_unique_number>: was clearing beyond - bitfield. - 20020326 Richard Gooch <rgooch@atnf.csiro.au> - Fixed bitfield data type for <devfs_*alloc_devnum>. - Made major bitfield type and initialiser 64 bit safe. - 20020413 Richard Gooch <rgooch@atnf.csiro.au> - Fixed shift warning on 64 bit machines. - 20020428 Richard Gooch <rgooch@atnf.csiro.au> - Copied and used macro for error messages from fs/devfs/base.c - 20021013 Richard Gooch <rgooch@atnf.csiro.au> - Documentation fix. - 20030101 Adam J. Richter <adam@yggdrasil.com> - Eliminate DEVFS_SPECIAL_{CHR,BLK}. Use mode_t instead. - 20030106 Christoph Hellwig <hch@infradead.org> - Rewrite devfs_{,de}alloc_devnum to look like C code. -*/ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/devfs_fs_kernel.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/genhd.h> -#include <linux/bitops.h> - -int devfs_register_tape(const char *name) -{ - char tname[32], dest[64]; - static unsigned int tape_counter; - unsigned int n = tape_counter++; - - sprintf(dest, "../%s", name); - sprintf(tname, "tapes/tape%u", n); - devfs_mk_symlink(tname, dest); - - return n; -} - -EXPORT_SYMBOL(devfs_register_tape); - -void devfs_unregister_tape(int num) -{ - if (num >= 0) - devfs_remove("tapes/tape%u", num); -} - -EXPORT_SYMBOL(devfs_unregister_tape); diff --git a/fs/direct-io.c b/fs/direct-io.c index 538fb0418fb..5981e17f46f 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -220,7 +220,8 @@ static void dio_complete(struct dio *dio, loff_t offset, ssize_t bytes) if (dio->end_io && dio->result) dio->end_io(dio->iocb, offset, bytes, dio->map_bh.b_private); if (dio->lock_type == DIO_LOCKING) - up_read(&dio->inode->i_alloc_sem); + /* lockdep: non-owner release */ + up_read_non_owner(&dio->inode->i_alloc_sem); } /* @@ -1261,7 +1262,8 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, } if (dio_lock_type == DIO_LOCKING) - down_read(&inode->i_alloc_sem); + /* lockdep: not the owner will release it */ + down_read_non_owner(&inode->i_alloc_sem); } /* diff --git a/fs/efs/inode.c b/fs/efs/inode.c index 180607f9314..174696f9bf1 100644 --- a/fs/efs/inode.c +++ b/fs/efs/inode.c @@ -21,7 +21,7 @@ static sector_t _efs_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,efs_get_block); } -static struct address_space_operations efs_aops = { +static const struct address_space_operations efs_aops = { .readpage = efs_readpage, .sync_page = block_sync_page, .bmap = _efs_bmap diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c index 3d9a350e3e7..e249cf733a6 100644 --- a/fs/efs/symlink.c +++ b/fs/efs/symlink.c @@ -53,6 +53,6 @@ fail: return err; } -struct address_space_operations efs_symlink_aops = { +const struct address_space_operations efs_symlink_aops = { .readpage = efs_symlink_readpage }; diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 9c677bbd0b0..19ffb043abb 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -120,7 +120,7 @@ struct epoll_filefd { */ struct wake_task_node { struct list_head llink; - task_t *task; + struct task_struct *task; wait_queue_head_t *wq; }; @@ -413,7 +413,7 @@ static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq) { int wake_nests = 0; unsigned long flags; - task_t *this_task = current; + struct task_struct *this_task = current; struct list_head *lsthead = &psw->wake_task_list, *lnk; struct wake_task_node *tncur; struct wake_task_node tnode; diff --git a/fs/exec.c b/fs/exec.c index c8494f513ea..8344ba73a2a 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -22,7 +22,6 @@ * formats. */ -#include <linux/config.h> #include <linux/slab.h> #include <linux/file.h> #include <linux/mman.h> diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 433a213a8bd..d4870432ecf 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -11,7 +11,6 @@ * David S. Miller (davem@caip.rutgers.edu), 1995 */ -#include <linux/config.h> #include "ext2.h" #include <linux/quotaops.h> #include <linux/sched.h> diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 9f74a62be55..e65a019fc7a 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -162,9 +162,9 @@ extern const struct file_operations ext2_file_operations; extern const struct file_operations ext2_xip_file_operations; /* inode.c */ -extern struct address_space_operations ext2_aops; -extern struct address_space_operations ext2_aops_xip; -extern struct address_space_operations ext2_nobh_aops; +extern const struct address_space_operations ext2_aops; +extern const struct address_space_operations ext2_aops_xip; +extern const struct address_space_operations ext2_nobh_aops; /* namei.c */ extern struct inode_operations ext2_dir_inode_operations; diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 308c252568c..de85c61c58c 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -12,7 +12,6 @@ * David S. Miller (davem@caip.rutgers.edu), 1995 */ -#include <linux/config.h> #include <linux/quotaops.h> #include <linux/sched.h> #include <linux/backing-dev.h> diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 04af9c45dce..fb4d3220eb8 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -684,7 +684,7 @@ ext2_writepages(struct address_space *mapping, struct writeback_control *wbc) return mpage_writepages(mapping, wbc, ext2_get_block); } -struct address_space_operations ext2_aops = { +const struct address_space_operations ext2_aops = { .readpage = ext2_readpage, .readpages = ext2_readpages, .writepage = ext2_writepage, @@ -697,12 +697,12 @@ struct address_space_operations ext2_aops = { .migratepage = buffer_migrate_page, }; -struct address_space_operations ext2_aops_xip = { +const struct address_space_operations ext2_aops_xip = { .bmap = ext2_bmap, .get_xip_page = ext2_get_xip_page, }; -struct address_space_operations ext2_nobh_aops = { +const struct address_space_operations ext2_nobh_aops = { .readpage = ext2_readpage, .readpages = ext2_readpages, .writepage = ext2_nobh_writepage, diff --git a/fs/ext2/super.c b/fs/ext2/super.c index d4233b2e643..f2702cda977 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -16,7 +16,6 @@ * David S. Miller (davem@caip.rutgers.edu), 1995 */ -#include <linux/config.h> #include <linux/module.h> #include <linux/string.h> #include <linux/fs.h> @@ -1158,7 +1157,7 @@ static ssize_t ext2_quota_write(struct super_block *sb, int type, struct buffer_head tmp_bh; struct buffer_head *bh; - mutex_lock(&inode->i_mutex); + mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); while (towrite > 0) { tocopy = sb->s_blocksize - offset < towrite ? sb->s_blocksize - offset : towrite; diff --git a/fs/ext2/xattr.h b/fs/ext2/xattr.h index 67cfeb66e89..bf8175b2ced 100644 --- a/fs/ext2/xattr.h +++ b/fs/ext2/xattr.h @@ -6,7 +6,6 @@ (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org> */ -#include <linux/config.h> #include <linux/init.h> #include <linux/xattr.h> diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index 96172e89ddc..a504a40d6d2 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -11,7 +11,6 @@ * David S. Miller (davem@caip.rutgers.edu), 1995 */ -#include <linux/config.h> #include <linux/time.h> #include <linux/capability.h> #include <linux/fs.h> diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 0321e1b9034..f804d5e9d60 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1698,7 +1698,7 @@ static int ext3_journalled_set_page_dirty(struct page *page) return __set_page_dirty_nobuffers(page); } -static struct address_space_operations ext3_ordered_aops = { +static const struct address_space_operations ext3_ordered_aops = { .readpage = ext3_readpage, .readpages = ext3_readpages, .writepage = ext3_ordered_writepage, @@ -1712,7 +1712,7 @@ static struct address_space_operations ext3_ordered_aops = { .migratepage = buffer_migrate_page, }; -static struct address_space_operations ext3_writeback_aops = { +static const struct address_space_operations ext3_writeback_aops = { .readpage = ext3_readpage, .readpages = ext3_readpages, .writepage = ext3_writeback_writepage, @@ -1726,7 +1726,7 @@ static struct address_space_operations ext3_writeback_aops = { .migratepage = buffer_migrate_page, }; -static struct address_space_operations ext3_journalled_aops = { +static const struct address_space_operations ext3_journalled_aops = { .readpage = ext3_readpage, .readpages = ext3_readpages, .writepage = ext3_journalled_writepage, diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index dfd811895d8..5e1337fd878 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c @@ -8,7 +8,6 @@ * This could probably be made into a module, because it is not often in use. */ -#include <linux/config.h> #define EXT3FS_DEBUG diff --git a/fs/ext3/super.c b/fs/ext3/super.c index b7483360a2d..813d589cc6c 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -16,7 +16,6 @@ * David S. Miller (davem@caip.rutgers.edu), 1995 */ -#include <linux/config.h> #include <linux/module.h> #include <linux/string.h> #include <linux/fs.h> @@ -2615,7 +2614,7 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type, struct buffer_head *bh; handle_t *handle = journal_current_handle(); - mutex_lock(&inode->i_mutex); + mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); while (towrite > 0) { tocopy = sb->s_blocksize - offset < towrite ? sb->s_blocksize - offset : towrite; diff --git a/fs/ext3/xattr.h b/fs/ext3/xattr.h index 2ceae38f3d4..6b1ae1c6182 100644 --- a/fs/ext3/xattr.h +++ b/fs/ext3/xattr.h @@ -6,7 +6,6 @@ (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org> */ -#include <linux/config.h> #include <linux/xattr.h> /* Magic value in attribute blocks */ diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 7c35d582ec1..31b7174176b 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -196,7 +196,7 @@ static sector_t _fat_bmap(struct address_space *mapping, sector_t block) return generic_block_bmap(mapping, block, fat_get_block); } -static struct address_space_operations fat_aops = { +static const struct address_space_operations fat_aops = { .readpage = fat_readpage, .readpages = fat_readpages, .writepage = fat_writepage, diff --git a/fs/file_table.c b/fs/file_table.c index 506d5307108..0131ba06e1e 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -5,7 +5,6 @@ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ -#include <linux/config.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/file.h> diff --git a/fs/freevxfs/vxfs_immed.c b/fs/freevxfs/vxfs_immed.c index 6f5df1700e9..4e25f3fbed8 100644 --- a/fs/freevxfs/vxfs_immed.c +++ b/fs/freevxfs/vxfs_immed.c @@ -56,7 +56,7 @@ struct inode_operations vxfs_immed_symlink_iops = { /* * Adress space operations for immed files and directories. */ -struct address_space_operations vxfs_immed_aops = { +const struct address_space_operations vxfs_immed_aops = { .readpage = vxfs_immed_readpage, }; diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c index f544aae9169..ca6a3971477 100644 --- a/fs/freevxfs/vxfs_inode.c +++ b/fs/freevxfs/vxfs_inode.c @@ -41,8 +41,8 @@ #include "vxfs_extern.h" -extern struct address_space_operations vxfs_aops; -extern struct address_space_operations vxfs_immed_aops; +extern const struct address_space_operations vxfs_aops; +extern const struct address_space_operations vxfs_immed_aops; extern struct inode_operations vxfs_immed_symlink_iops; @@ -295,7 +295,7 @@ vxfs_read_inode(struct inode *ip) { struct super_block *sbp = ip->i_sb; struct vxfs_inode_info *vip; - struct address_space_operations *aops; + const struct address_space_operations *aops; ino_t ino = ip->i_ino; if (!(vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist))) diff --git a/fs/freevxfs/vxfs_subr.c b/fs/freevxfs/vxfs_subr.c index c1be118fc06..decac62efe5 100644 --- a/fs/freevxfs/vxfs_subr.c +++ b/fs/freevxfs/vxfs_subr.c @@ -42,7 +42,7 @@ static int vxfs_readpage(struct file *, struct page *); static sector_t vxfs_bmap(struct address_space *, sector_t); -struct address_space_operations vxfs_aops = { +const struct address_space_operations vxfs_aops = { .readpage = vxfs_readpage, .bmap = vxfs_bmap, .sync_page = block_sync_page, diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 031b27a4bc9..892643dc9af 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -464,8 +464,8 @@ void sync_inodes_sb(struct super_block *sb, int wait) .range_start = 0, .range_end = LLONG_MAX, }; - unsigned long nr_dirty = read_page_state(nr_dirty); - unsigned long nr_unstable = read_page_state(nr_unstable); + unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY); + unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS); wbc.nr_to_write = nr_dirty + nr_unstable + (inodes_stat.nr_inodes - inodes_stat.nr_unused) + diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 28aa81eae2c..63614ed1633 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -770,7 +770,7 @@ static const struct file_operations fuse_direct_io_file_operations = { /* no mmap and sendfile */ }; -static struct address_space_operations fuse_file_aops = { +static const struct address_space_operations fuse_file_aops = { .readpage = fuse_readpage, .prepare_write = fuse_prepare_write, .commit_write = fuse_commit_write, diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h index 3ed8663a8db..735332dfd1b 100644 --- a/fs/hfs/hfs_fs.h +++ b/fs/hfs/hfs_fs.h @@ -182,8 +182,8 @@ extern void hfs_file_truncate(struct inode *); extern int hfs_get_block(struct inode *, sector_t, struct buffer_head *, int); /* inode.c */ -extern struct address_space_operations hfs_aops; -extern struct address_space_operations hfs_btree_aops; +extern const struct address_space_operations hfs_aops; +extern const struct address_space_operations hfs_btree_aops; extern struct inode *hfs_new_inode(struct inode *, struct qstr *, int); extern void hfs_inode_write_fork(struct inode *, struct hfs_extent *, __be32 *, __be32 *); diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 2d4ced22201..315cf44a90b 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -114,7 +114,7 @@ static int hfs_writepages(struct address_space *mapping, return mpage_writepages(mapping, wbc, hfs_get_block); } -struct address_space_operations hfs_btree_aops = { +const struct address_space_operations hfs_btree_aops = { .readpage = hfs_readpage, .writepage = hfs_writepage, .sync_page = block_sync_page, @@ -124,7 +124,7 @@ struct address_space_operations hfs_btree_aops = { .releasepage = hfs_releasepage, }; -struct address_space_operations hfs_aops = { +const struct address_space_operations hfs_aops = { .readpage = hfs_readpage, .writepage = hfs_writepage, .sync_page = block_sync_page, diff --git a/fs/hfs/super.c b/fs/hfs/super.c index d9227bf14e8..34937ee83ab 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -12,7 +12,6 @@ * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds */ -#include <linux/config.h> #include <linux/module.h> #include <linux/blkdev.h> #include <linux/mount.h> diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 7ae393637a0..8a1ca5ef7ad 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -323,8 +323,8 @@ int hfsplus_file_extend(struct inode *); void hfsplus_file_truncate(struct inode *); /* inode.c */ -extern struct address_space_operations hfsplus_aops; -extern struct address_space_operations hfsplus_btree_aops; +extern const struct address_space_operations hfsplus_aops; +extern const struct address_space_operations hfsplus_btree_aops; void hfsplus_inode_read_fork(struct inode *, struct hfsplus_fork_raw *); void hfsplus_inode_write_fork(struct inode *, struct hfsplus_fork_raw *); diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index acf66dba3e0..924ecdef809 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -109,7 +109,7 @@ static int hfsplus_writepages(struct address_space *mapping, return mpage_writepages(mapping, wbc, hfsplus_get_block); } -struct address_space_operations hfsplus_btree_aops = { +const struct address_space_operations hfsplus_btree_aops = { .readpage = hfsplus_readpage, .writepage = hfsplus_writepage, .sync_page = block_sync_page, @@ -119,7 +119,7 @@ struct address_space_operations hfsplus_btree_aops = { .releasepage = hfsplus_releasepage, }; -struct address_space_operations hfsplus_aops = { +const struct address_space_operations hfsplus_aops = { .readpage = hfsplus_readpage, .writepage = hfsplus_writepage, .sync_page = block_sync_page, diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 0a92fa2336a..d279d5924f2 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -7,7 +7,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/pagemap.h> diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 8e0d37743e7..b82e3d9c879 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -54,7 +54,7 @@ static int append = 0; static struct inode_operations hostfs_iops; static struct inode_operations hostfs_dir_iops; -static struct address_space_operations hostfs_link_aops; +static const struct address_space_operations hostfs_link_aops; #ifndef MODULE static int __init hostfs_args(char *options, int *add) @@ -518,7 +518,7 @@ int hostfs_commit_write(struct file *file, struct page *page, unsigned from, return(err); } -static struct address_space_operations hostfs_aops = { +static const struct address_space_operations hostfs_aops = { .writepage = hostfs_writepage, .readpage = hostfs_readpage, .set_page_dirty = __set_page_dirty_nobuffers, @@ -935,7 +935,7 @@ int hostfs_link_readpage(struct file *file, struct page *page) return(err); } -static struct address_space_operations hostfs_link_aops = { +static const struct address_space_operations hostfs_link_aops = { .readpage = hostfs_link_readpage, }; diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index d3b9fffe45a..d9eb19b7b8a 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -99,7 +99,7 @@ static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,hpfs_get_block); } -struct address_space_operations hpfs_aops = { +const struct address_space_operations hpfs_aops = { .readpage = hpfs_readpage, .writepage = hpfs_writepage, .sync_page = block_sync_page, diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index 29b7a3e5517..f687d54ed44 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -268,7 +268,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, char *, char *, int); int hpfs_file_fsync(struct file *, struct dentry *, int); extern const struct file_operations hpfs_file_ops; extern struct inode_operations hpfs_file_iops; -extern struct address_space_operations hpfs_aops; +extern const struct address_space_operations hpfs_aops; /* inode.c */ @@ -304,7 +304,7 @@ void hpfs_decide_conv(struct inode *, unsigned char *, unsigned); /* namei.c */ extern struct inode_operations hpfs_dir_iops; -extern struct address_space_operations hpfs_symlink_aops; +extern const struct address_space_operations hpfs_symlink_aops; static inline struct hpfs_inode_info *hpfs_i(struct inode *inode) { diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index a03abb12c61..59e7dc182a0 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -538,7 +538,7 @@ fail: return err; } -struct address_space_operations hpfs_symlink_aops = { +const struct address_space_operations hpfs_symlink_aops = { .readpage = hpfs_symlink_readpage }; diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index e6410d8edd0..6449cb69796 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -34,7 +34,7 @@ #define HUGETLBFS_MAGIC 0x958458f6 static struct super_operations hugetlbfs_ops; -static struct address_space_operations hugetlbfs_aops; +static const struct address_space_operations hugetlbfs_aops; const struct file_operations hugetlbfs_file_operations; static struct inode_operations hugetlbfs_dir_inode_operations; static struct inode_operations hugetlbfs_inode_operations; @@ -547,7 +547,7 @@ static void hugetlbfs_destroy_inode(struct inode *inode) kmem_cache_free(hugetlbfs_inode_cachep, HUGETLBFS_I(inode)); } -static struct address_space_operations hugetlbfs_aops = { +static const struct address_space_operations hugetlbfs_aops = { .readpage = hugetlbfs_readpage, .prepare_write = hugetlbfs_prepare_write, .commit_write = hugetlbfs_commit_write, diff --git a/fs/inode.c b/fs/inode.c index 3a2446a27d2..0bf9f0444a9 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -4,7 +4,6 @@ * (C) 1997 Linus Torvalds */ -#include <linux/config.h> #include <linux/fs.h> #include <linux/mm.h> #include <linux/dcache.h> @@ -102,7 +101,7 @@ static kmem_cache_t * inode_cachep __read_mostly; static struct inode *alloc_inode(struct super_block *sb) { - static struct address_space_operations empty_aops; + static const struct address_space_operations empty_aops; static struct inode_operations empty_iops; static const struct file_operations empty_fops; struct inode *inode; @@ -452,15 +451,14 @@ static void prune_icache(int nr_to_scan) nr_pruned++; } inodes_stat.nr_unused -= nr_pruned; + if (current_is_kswapd()) + __count_vm_events(KSWAPD_INODESTEAL, reap); + else + __count_vm_events(PGINODESTEAL, reap); spin_unlock(&inode_lock); dispose_list(&freeable); mutex_unlock(&iprune_mutex); - - if (current_is_kswapd()) - mod_page_state(kswapd_inodesteal, reap); - else - mod_page_state(pginodesteal, reap); } /* diff --git a/fs/ioctl.c b/fs/ioctl.c index f8aeec3ca10..4b7660b09ac 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -4,7 +4,6 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#include <linux/config.h> #include <linux/syscalls.h> #include <linux/mm.h> #include <linux/smp_lock.h> diff --git a/fs/ioprio.c b/fs/ioprio.c index 7fa76ed53c1..93aa5715f22 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -125,11 +125,24 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio) return ret; } +static int get_task_ioprio(struct task_struct *p) +{ + int ret; + + ret = security_task_getioprio(p); + if (ret) + goto out; + ret = p->ioprio; +out: + return ret; +} + asmlinkage long sys_ioprio_get(int which, int who) { struct task_struct *g, *p; struct user_struct *user; int ret = -ESRCH; + int tmpio; read_lock_irq(&tasklist_lock); switch (which) { @@ -139,16 +152,19 @@ asmlinkage long sys_ioprio_get(int which, int who) else p = find_task_by_pid(who); if (p) - ret = p->ioprio; + ret = get_task_ioprio(p); break; case IOPRIO_WHO_PGRP: if (!who) who = process_group(current); do_each_task_pid(who, PIDTYPE_PGID, p) { + tmpio = get_task_ioprio(p); + if (tmpio < 0) + continue; if (ret == -ESRCH) - ret = p->ioprio; + ret = tmpio; else - ret = ioprio_best(ret, p->ioprio); + ret = ioprio_best(ret, tmpio); } while_each_task_pid(who, PIDTYPE_PGID, p); break; case IOPRIO_WHO_USER: @@ -163,10 +179,13 @@ asmlinkage long sys_ioprio_get(int which, int who) do_each_thread(g, p) { if (p->uid != user->uid) continue; + tmpio = get_task_ioprio(p); + if (tmpio < 0) + continue; if (ret == -ESRCH) - ret = p->ioprio; + ret = tmpio; else - ret = ioprio_best(ret, p->ioprio); + ret = ioprio_best(ret, tmpio); } while_each_thread(g, p); if (who) diff --git a/fs/isofs/compress.c b/fs/isofs/compress.c index 4917315db73..731816332b1 100644 --- a/fs/isofs/compress.c +++ b/fs/isofs/compress.c @@ -16,7 +16,6 @@ * Transparent decompression of files on an iso9660 filesystem */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> @@ -312,7 +311,7 @@ eio: return err; } -struct address_space_operations zisofs_aops = { +const struct address_space_operations zisofs_aops = { .readpage = zisofs_readpage, /* No sync_page operation supported? */ /* No bmap operation supported */ diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c index 5440ea292c6..27e276987fd 100644 --- a/fs/isofs/dir.c +++ b/fs/isofs/dir.c @@ -10,7 +10,6 @@ * * isofs directory handling functions */ -#include <linux/config.h> #include <linux/smp_lock.h> #include "isofs.h" diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 3f9c8ba1fa1..14391361c88 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -11,7 +11,6 @@ * 2004 Paul Serice - NFS Export Operations */ -#include <linux/config.h> #include <linux/init.h> #include <linux/module.h> @@ -1054,7 +1053,7 @@ static sector_t _isofs_bmap(struct address_space *mapping, sector_t block) return generic_block_bmap(mapping,block,isofs_get_block); } -static struct address_space_operations isofs_aops = { +static const struct address_space_operations isofs_aops = { .readpage = isofs_readpage, .sync_page = block_sync_page, .bmap = _isofs_bmap diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h index b87ba066f5e..e6308c8b573 100644 --- a/fs/isofs/isofs.h +++ b/fs/isofs/isofs.h @@ -176,5 +176,5 @@ isofs_normalize_block_and_offset(struct iso_directory_record* de, extern struct inode_operations isofs_dir_inode_operations; extern const struct file_operations isofs_dir_operations; -extern struct address_space_operations isofs_symlink_aops; +extern const struct address_space_operations isofs_symlink_aops; extern struct export_operations isofs_export_ops; diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 4326cb47f8f..f3a1db3098d 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -754,6 +754,6 @@ error: return -EIO; } -struct address_space_operations isofs_symlink_aops = { +const struct address_space_operations isofs_symlink_aops = { .readpage = rock_ridge_symlink_readpage }; diff --git a/fs/isofs/zisofs.h b/fs/isofs/zisofs.h index d78485d101c..27379570915 100644 --- a/fs/isofs/zisofs.h +++ b/fs/isofs/zisofs.h @@ -15,7 +15,7 @@ */ #ifdef CONFIG_ZISOFS -extern struct address_space_operations zisofs_aops; +extern const struct address_space_operations zisofs_aops; extern int __init zisofs_init(void); extern void zisofs_cleanup(void); #endif diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index 9e46ea6da75..93068697a9b 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -59,7 +59,7 @@ static const struct file_operations jffs_file_operations; static struct inode_operations jffs_file_inode_operations; static const struct file_operations jffs_dir_operations; static struct inode_operations jffs_dir_inode_operations; -static struct address_space_operations jffs_address_operations; +static const struct address_space_operations jffs_address_operations; kmem_cache_t *node_cache = NULL; kmem_cache_t *fm_cache = NULL; @@ -1614,7 +1614,7 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, } /* jffs_ioctl() */ -static struct address_space_operations jffs_address_operations = { +static const struct address_space_operations jffs_address_operations = { .readpage = jffs_readpage, .prepare_write = jffs_prepare_write, .commit_write = jffs_commit_write, diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c index 5371a403130..9000f1effed 100644 --- a/fs/jffs/intrep.c +++ b/fs/jffs/intrep.c @@ -55,7 +55,6 @@ * */ -#include <linux/config.h> #include <linux/types.h> #include <linux/slab.h> #include <linux/jffs.h> diff --git a/fs/jffs/jffs_fm.h b/fs/jffs/jffs_fm.h index c794d923df2..9ee6ad29eff 100644 --- a/fs/jffs/jffs_fm.h +++ b/fs/jffs/jffs_fm.h @@ -20,7 +20,6 @@ #ifndef __LINUX_JFFS_FM_H__ #define __LINUX_JFFS_FM_H__ -#include <linux/config.h> #include <linux/types.h> #include <linux/jffs.h> #include <linux/mtd/mtd.h> diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 5c63e0cdcf4..3681d0728ac 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c @@ -15,7 +15,6 @@ #error "The userspace support got too messy and was removed. Update your mkfs.jffs2" #endif -#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/slab.h> diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h index 5fa494a792b..3daf3bca037 100644 --- a/fs/jffs2/debug.h +++ b/fs/jffs2/debug.h @@ -13,7 +13,6 @@ #ifndef _JFFS2_DEBUG_H_ #define _JFFS2_DEBUG_H_ -#include <linux/config.h> #ifndef CONFIG_JFFS2_FS_DEBUG #define CONFIG_JFFS2_FS_DEBUG 0 diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index bb8844f40e4..3ed6e3e120b 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -62,7 +62,7 @@ struct inode_operations jffs2_file_inode_operations = .removexattr = jffs2_removexattr }; -struct address_space_operations jffs2_file_address_operations = +const struct address_space_operations jffs2_file_address_operations = { .readpage = jffs2_readpage, .prepare_write =jffs2_prepare_write, diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 97caa77d60c..4780f82825d 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -12,7 +12,6 @@ */ #include <linux/capability.h> -#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/fs.h> diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index be6d4a4dd8e..cae92c14116 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -14,7 +14,6 @@ #ifndef __JFFS2_NODELIST_H__ #define __JFFS2_NODELIST_H__ -#include <linux/config.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/jffs2.h> diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 6b522356540..9f41fc01a37 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -158,7 +158,7 @@ extern struct inode_operations jffs2_dir_inode_operations; /* file.c */ extern const struct file_operations jffs2_file_operations; extern struct inode_operations jffs2_file_inode_operations; -extern struct address_space_operations jffs2_file_address_operations; +extern const struct address_space_operations jffs2_file_address_operations; int jffs2_fsync(struct file *, struct dentry *, int); int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg); diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 2378a662c25..68e3953419b 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -11,7 +11,6 @@ * */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 04eb78f1252..43e3f566aad 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -305,7 +305,7 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb, offset, nr_segs, jfs_get_block, NULL); } -struct address_space_operations jfs_aops = { +const struct address_space_operations jfs_aops = { .readpage = jfs_readpage, .readpages = jfs_readpages, .writepage = jfs_writepage, diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h index c3007267446..b5c7da6190d 100644 --- a/fs/jfs/jfs_inode.h +++ b/fs/jfs/jfs_inode.h @@ -33,7 +33,7 @@ extern void jfs_free_zero_link(struct inode *); extern struct dentry *jfs_get_parent(struct dentry *dentry); extern void jfs_set_inode_flags(struct inode *); -extern struct address_space_operations jfs_aops; +extern const struct address_space_operations jfs_aops; extern struct inode_operations jfs_dir_inode_operations; extern const struct file_operations jfs_dir_operations; extern struct inode_operations jfs_file_inode_operations; diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 7f6e8803970..e1e0a6e6ebd 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -577,7 +577,7 @@ static void metapage_invalidatepage(struct page *page, unsigned long offset) metapage_releasepage(page, 0); } -struct address_space_operations jfs_metapage_aops = { +const struct address_space_operations jfs_metapage_aops = { .readpage = metapage_readpage, .writepage = metapage_writepage, .sync_page = block_sync_page, diff --git a/fs/jfs/jfs_metapage.h b/fs/jfs/jfs_metapage.h index f0b7d3282b0..d17a3290f5a 100644 --- a/fs/jfs/jfs_metapage.h +++ b/fs/jfs/jfs_metapage.h @@ -139,7 +139,7 @@ static inline void metapage_homeok(struct metapage *mp) put_metapage(mp); } -extern struct address_space_operations jfs_metapage_aops; +extern const struct address_space_operations jfs_metapage_aops; /* * This routines invalidate all pages for an extent. diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index ac3d66948e8..10c46231ce1 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -842,7 +842,7 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp, TXN_UNLOCK(); release_metapage(mp); TXN_LOCK(); - xtid = tlck->tid; /* reaquire after dropping TXN_LOCK */ + xtid = tlck->tid; /* reacquire after dropping TXN_LOCK */ jfs_info("txLock: in waitLock, tid = %d, xtid = %d, lid = %d", tid, xtid, lid); diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 73d2aba084c..4f6cfebc82d 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -18,7 +18,6 @@ */ #include <linux/fs.h> -#include <linux/config.h> #include <linux/module.h> #include <linux/parser.h> #include <linux/completion.h> diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 4db62098d3f..5980c45998c 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -6,7 +6,6 @@ * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> #include <linux/errno.h> diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index fd56c8872f3..9a991b52c64 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -12,7 +12,6 @@ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> #include <linux/sysctl.h> diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 3ef739120df..baf5ae51348 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -20,7 +20,6 @@ * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> */ -#include <linux/config.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/kernel.h> diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index d210cf304e9..dbb66a3b5cd 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -7,7 +7,6 @@ * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> */ -#include <linux/config.h> #include <linux/types.h> #include <linux/time.h> #include <linux/slab.h> diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index a570e5c8a93..2a4df9b3779 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -6,7 +6,6 @@ * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> */ -#include <linux/config.h> #include <linux/types.h> #include <linux/string.h> #include <linux/time.h> diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index f22a3764461..033ea4ac2c3 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -6,7 +6,6 @@ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */ -#include <linux/config.h> #include <linux/types.h> #include <linux/sched.h> #include <linux/utsname.h> diff --git a/fs/minix/inode.c b/fs/minix/inode.c index a6fb509b734..9ea91c5eeb7 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -335,7 +335,7 @@ static sector_t minix_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,minix_get_block); } -static struct address_space_operations minix_aops = { +static const struct address_space_operations minix_aops = { .readpage = minix_readpage, .writepage = minix_writepage, .sync_page = block_sync_page, diff --git a/fs/namei.c b/fs/namei.c index c784e8bb57a..c9750d755af 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1423,7 +1423,7 @@ struct dentry *lock_rename(struct dentry *p1, struct dentry *p2) struct dentry *p; if (p1 == p2) { - mutex_lock(&p1->d_inode->i_mutex); + mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); return NULL; } @@ -1431,22 +1431,22 @@ struct dentry *lock_rename(struct dentry *p1, struct dentry *p2) for (p = p1; p->d_parent != p; p = p->d_parent) { if (p->d_parent == p2) { - mutex_lock(&p2->d_inode->i_mutex); - mutex_lock(&p1->d_inode->i_mutex); + mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_CHILD); return p; } } for (p = p2; p->d_parent != p; p = p->d_parent) { if (p->d_parent == p1) { - mutex_lock(&p1->d_inode->i_mutex); - mutex_lock(&p2->d_inode->i_mutex); + mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD); return p; } } - mutex_lock(&p1->d_inode->i_mutex); - mutex_lock(&p2->d_inode->i_mutex); + mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD); return NULL; } @@ -1751,7 +1751,7 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir) { struct dentry *dentry = ERR_PTR(-EEXIST); - mutex_lock(&nd->dentry->d_inode->i_mutex); + mutex_lock_nested(&nd->dentry->d_inode->i_mutex, I_MUTEX_PARENT); /* * Yucky last component or no last component at all? * (foo/., foo/.., /////) @@ -2008,7 +2008,7 @@ static long do_rmdir(int dfd, const char __user *pathname) error = -EBUSY; goto exit1; } - mutex_lock(&nd.dentry->d_inode->i_mutex); + mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT); dentry = lookup_hash(&nd); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { @@ -2082,7 +2082,7 @@ static long do_unlinkat(int dfd, const char __user *pathname) error = -EISDIR; if (nd.last_type != LAST_NORM) goto exit1; - mutex_lock(&nd.dentry->d_inode->i_mutex); + mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT); dentry = lookup_hash(&nd); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { diff --git a/fs/namespace.c b/fs/namespace.c index b3ed212ea41..fa7ed6a9fc2 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -8,7 +8,6 @@ * Heavily rewritten. */ -#include <linux/config.h> #include <linux/syscalls.h> #include <linux/slab.h> #include <linux/sched.h> diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index f0860c602d8..b4ee89250e9 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -10,7 +10,6 @@ * */ -#include <linux/config.h> #include <linux/time.h> #include <linux/errno.h> diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 90d2ea28f33..1ddf77b0b82 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -9,7 +9,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <asm/system.h> @@ -105,7 +104,7 @@ static struct super_operations ncp_sops = extern struct dentry_operations ncp_root_dentry_operations; #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) -extern struct address_space_operations ncp_symlink_aops; +extern const struct address_space_operations ncp_symlink_aops; extern int ncp_symlink(struct inode*, struct dentry*, const char*); #endif diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index eb3813ad136..42039fe0653 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -7,7 +7,6 @@ * */ -#include <linux/config.h> #include <asm/uaccess.h> #include <linux/capability.h> diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c index 52d60c3d899..e7d5a3097fe 100644 --- a/fs/ncpfs/mmap.c +++ b/fs/ncpfs/mmap.c @@ -93,7 +93,7 @@ static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area, */ if (type) *type = VM_FAULT_MAJOR; - inc_page_state(pgmajfault); + count_vm_event(PGMAJFAULT); return page; } diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c index d9ebf6439f5..551e0bac7aa 100644 --- a/fs/ncpfs/ncplib_kernel.c +++ b/fs/ncpfs/ncplib_kernel.c @@ -10,7 +10,6 @@ */ -#include <linux/config.h> #include "ncplib_kernel.h" diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index 799e5c2bec5..2441d1ab57d 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h @@ -12,7 +12,6 @@ #ifndef _NCPLIB_H #define _NCPLIB_H -#include <linux/config.h> #include <linux/fs.h> #include <linux/types.h> diff --git a/fs/ncpfs/ncpsign_kernel.c b/fs/ncpfs/ncpsign_kernel.c index a6ec90cd889..749a18d3359 100644 --- a/fs/ncpfs/ncpsign_kernel.c +++ b/fs/ncpfs/ncpsign_kernel.c @@ -5,7 +5,6 @@ * */ -#include <linux/config.h> #ifdef CONFIG_NCPFS_PACKET_SIGNING diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c index 8783eb7ec64..11c2b252ebe 100644 --- a/fs/ncpfs/sock.c +++ b/fs/ncpfs/sock.c @@ -8,7 +8,6 @@ * */ -#include <linux/config.h> #include <linux/time.h> #include <linux/errno.h> diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c index e935f1b34bc..ca92c240663 100644 --- a/fs/ncpfs/symlink.c +++ b/fs/ncpfs/symlink.c @@ -20,7 +20,6 @@ * */ -#include <linux/config.h> #include <asm/uaccess.h> @@ -99,7 +98,7 @@ fail: /* * symlinks can't do much... */ -struct address_space_operations ncp_symlink_aops = { +const struct address_space_operations ncp_symlink_aops = { .readpage = ncp_symlink_readpage, }; diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index d53f8c6a9ec..fe0a6b8ac14 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -6,7 +6,6 @@ * NFSv4 callback handling */ -#include <linux/config.h> #include <linux/completion.h> #include <linux/ip.h> #include <linux/module.h> diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 462cfceb50c..7719483ecdf 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -5,7 +5,6 @@ * * NFSv4 callback procedures */ -#include <linux/config.h> #include <linux/nfs4.h> #include <linux/nfs_fs.h> #include "nfs4_fs.h" diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index c92991328d9..29f93219205 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -5,7 +5,6 @@ * * NFSv4 callback encode/decode procedures */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/sunrpc/svc.h> #include <linux/nfs4.h> diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index d3be923d4e4..9540a316c05 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -6,7 +6,6 @@ * NFS file delegation management * */ -#include <linux/config.h> #include <linux/completion.h> #include <linux/kthread.h> #include <linux/module.h> diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 8ca9707be6c..4cdd1b499e3 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -38,7 +38,6 @@ * */ -#include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> diff --git a/fs/nfs/file.c b/fs/nfs/file.c index add28913883..cc2b874ad5a 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -315,7 +315,7 @@ static int nfs_release_page(struct page *page, gfp_t gfp) return !nfs_wb_page(page->mapping->host, page); } -struct address_space_operations nfs_file_aops = { +const struct address_space_operations nfs_file_aops = { .readpage = nfs_readpage, .readpages = nfs_readpages, .set_page_dirty = __set_page_dirty_nobuffers, diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index c5b916605fb..d349fb2245d 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -13,7 +13,6 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 4fe51c1292b..e4f4e5def0f 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -81,9 +81,9 @@ extern struct file_system_type clone_nfs_fs_type; #ifdef CONFIG_NFS_V4 extern struct file_system_type clone_nfs4_fs_type; #endif -#ifdef CONFIG_PROC_FS + extern struct rpc_stat nfs_rpcstat; -#endif + extern int __init register_nfs_fs(void); extern void __exit unregister_nfs_fs(void); diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 96e5b82c153..090a36b07a2 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -38,7 +38,6 @@ * subsequent patch. */ -#include <linux/config.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/nfs_fs.h> diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index d89f6fb3b3a..36e902a88ca 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -9,7 +9,6 @@ * */ -#include <linux/config.h> #include <linux/slab.h> #include <linux/file.h> #include <linux/sunrpc/clnt.h> @@ -315,6 +314,7 @@ nfs_scan_lock_dirty(struct nfs_inode *nfsi, struct list_head *dst, req->wb_index, NFS_PAGE_TAG_DIRTY); nfs_list_remove_request(req); nfs_list_add_request(req, dst); + dec_zone_page_state(req->wb_page, NR_FILE_DIRTY); res++; } } diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 32cf3773af0..52bf634260a 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -15,7 +15,6 @@ * within the RPC code when root squashing is suspected. */ -#include <linux/config.h> #include <linux/time.h> #include <linux/kernel.h> #include <linux/errno.h> diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c index db61e51bb15..2fe3403c240 100644 --- a/fs/nfs/sysctl.c +++ b/fs/nfs/sysctl.c @@ -3,7 +3,6 @@ * * Sysctl interface to NFS parameters */ -#include <linux/config.h> #include <linux/types.h> #include <linux/linkage.h> #include <linux/ctype.h> diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 8fccb9cb173..bca5734ca9f 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -46,7 +46,6 @@ * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de> */ -#include <linux/config.h> #include <linux/types.h> #include <linux/slab.h> #include <linux/mm.h> @@ -497,7 +496,7 @@ nfs_mark_request_dirty(struct nfs_page *req) nfs_list_add_request(req, &nfsi->dirty); nfsi->ndirty++; spin_unlock(&nfsi->req_lock); - inc_page_state(nr_dirty); + inc_zone_page_state(req->wb_page, NR_FILE_DIRTY); mark_inode_dirty(inode); } @@ -525,7 +524,7 @@ nfs_mark_request_commit(struct nfs_page *req) nfs_list_add_request(req, &nfsi->commit); nfsi->ncommit++; spin_unlock(&nfsi->req_lock); - inc_page_state(nr_unstable); + inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); mark_inode_dirty(inode); } #endif @@ -609,7 +608,6 @@ nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_sta if (nfsi->ndirty != 0) { res = nfs_scan_lock_dirty(nfsi, dst, idx_start, npages); nfsi->ndirty -= res; - sub_page_state(nr_dirty,res); if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)) printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n"); } @@ -1394,7 +1392,6 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) { struct nfs_write_data *data = calldata; struct nfs_page *req; - int res = 0; dprintk("NFS: %4d nfs_commit_done (status %d)\n", task->tk_pid, task->tk_status); @@ -1406,6 +1403,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) while (!list_empty(&data->pages)) { req = nfs_list_entry(data->pages.next); nfs_list_remove_request(req); + dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); dprintk("NFS: commit (%s/%Ld %d@%Ld)", req->wb_context->dentry->d_inode->i_sb->s_id, @@ -1432,9 +1430,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) nfs_mark_request_dirty(req); next: nfs_clear_page_writeback(req); - res++; } - sub_page_state(nr_unstable,res); } static const struct rpc_call_ops nfs_commit_ops = { diff --git a/fs/nfsctl.c b/fs/nfsctl.c index a5a18d4aca4..c043136a82c 100644 --- a/fs/nfsctl.c +++ b/fs/nfsctl.c @@ -4,7 +4,6 @@ * This should eventually move to userland. * */ -#include <linux/config.h> #include <linux/types.h> #include <linux/file.h> #include <linux/fs.h> diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 3eec30000f3..01bc68c628a 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -126,7 +126,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) if (*ep) goto out; dprintk("found fsidtype %d\n", fsidtype); - if (fsidtype > 2) + if (key_len(fsidtype)==0) /* invalid type */ goto out; if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) goto out; diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index dbaf3f93f32..54b37b1d2e3 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -33,7 +33,6 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/list.h> #include <linux/inet.h> diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 4b6aa60dfce..bea6b947811 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -34,7 +34,6 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/init.h> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7c7d01672d3..9daa0b9feb8 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1237,8 +1237,15 @@ find_file(struct inode *ino) return NULL; } -#define TEST_ACCESS(x) ((x > 0 || x < 4)?1:0) -#define TEST_DENY(x) ((x >= 0 || x < 5)?1:0) +static int access_valid(u32 x) +{ + return (x > 0 && x < 4); +} + +static int deny_valid(u32 x) +{ + return (x >= 0 && x < 5); +} static void set_access(unsigned int *access, unsigned long bmap) { @@ -1745,7 +1752,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf int status; status = nfserr_inval; - if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny)) + if (!access_valid(open->op_share_access) + || !deny_valid(open->op_share_deny)) goto out; /* * Lookup file; if found, lookup stateid and check open request, @@ -1782,10 +1790,10 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf } else { /* Stateid was not found, this is a new OPEN */ int flags = 0; + if (open->op_share_access & NFS4_SHARE_ACCESS_READ) + flags |= MAY_READ; if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) - flags = MAY_WRITE; - else - flags = MAY_READ; + flags |= MAY_WRITE; status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags); if (status) goto out; @@ -2070,16 +2078,12 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl if (!stateid->si_fileid) { /* delegation stateid */ if(!(dp = find_delegation_stateid(ino, stateid))) { dprintk("NFSD: delegation stateid not found\n"); - if (nfs4_in_grace()) - status = nfserr_grace; goto out; } stidp = &dp->dl_stateid; } else { /* open or lock stateid */ if (!(stp = find_stateid(stateid, flags))) { dprintk("NFSD: open or lock stateid not found\n"); - if (nfs4_in_grace()) - status = nfserr_grace; goto out; } if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) @@ -2252,8 +2256,9 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs (int)current_fh->fh_dentry->d_name.len, current_fh->fh_dentry->d_name.name); - if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) - goto out; + status = fh_verify(rqstp, current_fh, S_IFREG, 0); + if (status) + return status; nfs4_lock_state(); @@ -2320,7 +2325,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct n (int)current_fh->fh_dentry->d_name.len, current_fh->fh_dentry->d_name.name); - if (!TEST_ACCESS(od->od_share_access) || !TEST_DENY(od->od_share_deny)) + if (!access_valid(od->od_share_access) + || !deny_valid(od->od_share_deny)) return nfserr_inval; nfs4_lock_state(); diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index a1810e6a93e..7046ac9cf97 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -6,7 +6,6 @@ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */ -#include <linux/config.h> #include <linux/module.h> #include <linux/linkage.h> diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 3f2ec2e6d06..ecc439d2565 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -187,13 +187,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) goto out; } - /* Set user creds for this exportpoint */ - error = nfsd_setuser(rqstp, exp); - if (error) { - error = nfserrno(error); - goto out; - } - /* * Look up the dentry using the NFS file handle. */ @@ -251,6 +244,14 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) } cache_get(&exp->h); + /* Set user creds for this exportpoint; necessary even in the "just + * checking" case because this may be a filehandle that was created by + * fh_compose, and that is about to be used in another nfsv4 compound + * operation */ + error = nfserrno(nfsd_setuser(rqstp, exp)); + if (error) + goto out; + error = nfsd_mode_check(rqstp, dentry->d_inode->i_mode, type); if (error) goto out; @@ -312,8 +313,8 @@ int fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, struct svc_fh *ref_fh) { /* ref_fh is a reference file handle. - * if it is non-null, then we should compose a filehandle which is - * of the same version, where possible. + * if it is non-null and for the same filesystem, then we should compose + * a filehandle which is of the same version, where possible. * Currently, that means that if ref_fh->fh_handle.fh_version == 0xca * Then create a 32byte filehandle using nfs_fhbase_old * @@ -332,7 +333,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st parent->d_name.name, dentry->d_name.name, (inode ? inode->i_ino : 0)); - if (ref_fh) { + if (ref_fh && ref_fh->fh_export == exp) { ref_fh_version = ref_fh->fh_handle.fh_version; if (ref_fh_version == 0xca) ref_fh_fsid_type = 0; @@ -461,7 +462,7 @@ fh_update(struct svc_fh *fhp) } else { int size; if (fhp->fh_handle.fh_fileid_type != 0) - goto out_uptodate; + goto out; datap = fhp->fh_handle.fh_auth+ fhp->fh_handle.fh_size/4 -1; size = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4; @@ -481,10 +482,6 @@ out_negative: printk(KERN_ERR "fh_update: %s/%s still negative!\n", dentry->d_parent->d_name.name, dentry->d_name.name); goto out; -out_uptodate: - printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n", - dentry->d_parent->d_name.name, dentry->d_name.name); - goto out; } /* diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 3790727e5df..ec1decf29ba 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -8,7 +8,6 @@ * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> */ -#include <linux/config.h> #include <linux/module.h> #include <linux/time.h> diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 245eaa1fb59..c9e3b5a8fe0 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -16,7 +16,6 @@ * Zerocpy NFS support (C) 2002 Hirokazu Takahashi <taka@valinux.co.jp> */ -#include <linux/config.h> #include <linux/string.h> #include <linux/time.h> #include <linux/errno.h> @@ -673,7 +672,10 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, goto out_nfserr; if (access & MAY_WRITE) { - flags = O_WRONLY|O_LARGEFILE; + if (access & MAY_READ) + flags = O_RDWR|O_LARGEFILE; + else + flags = O_WRONLY|O_LARGEFILE; DQUOT_INIT(inode); } @@ -834,7 +836,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, if (ra && ra->p_set) file->f_ra = ra->p_ra; - if (file->f_op->sendfile) { + if (file->f_op->sendfile && rqstp->rq_sendfile_ok) { svc_pushback_unused_pages(rqstp); err = file->f_op->sendfile(file, &offset, *count, nfsd_read_actor, rqstp); @@ -1517,14 +1519,15 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, err = nfserrno(err); } - fh_unlock(ffhp); dput(dnew); +out_unlock: + fh_unlock(ffhp); out: return err; out_nfserr: err = nfserrno(err); - goto out; + goto out_unlock; } /* @@ -1553,7 +1556,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, tdir = tdentry->d_inode; err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev; - if (fdir->i_sb != tdir->i_sb) + if (ffhp->fh_export != tfhp->fh_export) goto out; err = nfserr_perm; diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index a912debcd20..9de6b495f11 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c @@ -10,7 +10,6 @@ #include <linux/module.h> #include <linux/string.h> -#include <linux/config.h> #include <linux/nls.h> #include <linux/kernel.h> #include <linux/errno.h> diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 580412d330c..bc579bfdfbd 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -1544,7 +1544,7 @@ err_out: /** * ntfs_aops - general address space operations for inodes and attributes */ -struct address_space_operations ntfs_aops = { +const struct address_space_operations ntfs_aops = { .readpage = ntfs_readpage, /* Fill page with data. */ .sync_page = block_sync_page, /* Currently, just unplugs the disk request queue. */ @@ -1560,7 +1560,7 @@ struct address_space_operations ntfs_aops = { * ntfs_mst_aops - general address space operations for mst protecteed inodes * and attributes */ -struct address_space_operations ntfs_mst_aops = { +const struct address_space_operations ntfs_mst_aops = { .readpage = ntfs_readpage, /* Fill page with data. */ .sync_page = block_sync_page, /* Currently, just unplugs the disk request queue. */ diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 4c86b7e1d1e..d313f356e66 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -367,6 +367,12 @@ static void ntfs_destroy_extent_inode(ntfs_inode *ni) kmem_cache_free(ntfs_inode_cache, ni); } +/* + * The attribute runlist lock has separate locking rules from the + * normal runlist lock, so split the two lock-classes: + */ +static struct lock_class_key attr_list_rl_lock_class; + /** * __ntfs_init_inode - initialize ntfs specific part of an inode * @sb: super block of mounted volume @@ -394,6 +400,8 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni) ni->attr_list_size = 0; ni->attr_list = NULL; ntfs_init_runlist(&ni->attr_list_rl); + lockdep_set_class(&ni->attr_list_rl.lock, + &attr_list_rl_lock_class); ni->itype.index.bmp_ino = NULL; ni->itype.index.block_size = 0; ni->itype.index.vcn_size = 0; @@ -405,6 +413,13 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni) ni->ext.base_ntfs_ino = NULL; } +/* + * Extent inodes get MFT-mapped in a nested way, while the base inode + * is still mapped. Teach this nesting to the lock validator by creating + * a separate class for nested inode's mrec_lock's: + */ +static struct lock_class_key extent_inode_mrec_lock_key; + inline ntfs_inode *ntfs_new_extent_inode(struct super_block *sb, unsigned long mft_no) { @@ -413,6 +428,7 @@ inline ntfs_inode *ntfs_new_extent_inode(struct super_block *sb, ntfs_debug("Entering."); if (likely(ni != NULL)) { __ntfs_init_inode(sb, ni); + lockdep_set_class(&ni->mrec_lock, &extent_inode_mrec_lock_key); ni->mft_no = mft_no; ni->type = AT_UNUSED; ni->name = NULL; @@ -1722,6 +1738,15 @@ err_out: return err; } +/* + * The MFT inode has special locking, so teach the lock validator + * about this by splitting off the locking rules of the MFT from + * the locking rules of other inodes. The MFT inode can never be + * accessed from the VFS side (or even internally), only by the + * map_mft functions. + */ +static struct lock_class_key mft_ni_runlist_lock_key, mft_ni_mrec_lock_key; + /** * ntfs_read_inode_mount - special read_inode for mount time use only * @vi: inode to read @@ -2148,6 +2173,14 @@ int ntfs_read_inode_mount(struct inode *vi) ntfs_attr_put_search_ctx(ctx); ntfs_debug("Done."); ntfs_free(m); + + /* + * Split the locking rules of the MFT inode from the + * locking rules of other inodes: + */ + lockdep_set_class(&ni->runlist.lock, &mft_ni_runlist_lock_key); + lockdep_set_class(&ni->mrec_lock, &mft_ni_mrec_lock_key); + return 0; em_put_err_out: diff --git a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h index bf7b3d7c093..ddd3d503097 100644 --- a/fs/ntfs/ntfs.h +++ b/fs/ntfs/ntfs.h @@ -57,8 +57,8 @@ extern struct kmem_cache *ntfs_attr_ctx_cache; extern struct kmem_cache *ntfs_index_ctx_cache; /* The various operations structs defined throughout the driver files. */ -extern struct address_space_operations ntfs_aops; -extern struct address_space_operations ntfs_mst_aops; +extern const struct address_space_operations ntfs_aops; +extern const struct address_space_operations ntfs_mst_aops; extern const struct file_operations ntfs_file_ops; extern struct inode_operations ntfs_file_inode_ops; diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 0e14acea3f8..74e0ee8fce7 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -1724,6 +1724,14 @@ upcase_failed: return FALSE; } +/* + * The lcn and mft bitmap inodes are NTFS-internal inodes with + * their own special locking rules: + */ +static struct lock_class_key + lcnbmp_runlist_lock_key, lcnbmp_mrec_lock_key, + mftbmp_runlist_lock_key, mftbmp_mrec_lock_key; + /** * load_system_files - open the system files using normal functions * @vol: ntfs super block describing device whose system files to load @@ -1780,6 +1788,10 @@ static BOOL load_system_files(ntfs_volume *vol) ntfs_error(sb, "Failed to load $MFT/$BITMAP attribute."); goto iput_mirr_err_out; } + lockdep_set_class(&NTFS_I(vol->mftbmp_ino)->runlist.lock, + &mftbmp_runlist_lock_key); + lockdep_set_class(&NTFS_I(vol->mftbmp_ino)->mrec_lock, + &mftbmp_mrec_lock_key); /* Read upcase table and setup @vol->upcase and @vol->upcase_len. */ if (!load_and_init_upcase(vol)) goto iput_mftbmp_err_out; @@ -1802,6 +1814,11 @@ static BOOL load_system_files(ntfs_volume *vol) iput(vol->lcnbmp_ino); goto bitmap_failed; } + lockdep_set_class(&NTFS_I(vol->lcnbmp_ino)->runlist.lock, + &lcnbmp_runlist_lock_key); + lockdep_set_class(&NTFS_I(vol->lcnbmp_ino)->mrec_lock, + &lcnbmp_mrec_lock_key); + NInoSetSparseDisabled(NTFS_I(vol->lcnbmp_ino)); if ((vol->nr_clusters + 7) >> 3 > i_size_read(vol->lcnbmp_ino)) { iput(vol->lcnbmp_ino); @@ -2743,6 +2760,17 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) struct inode *tmp_ino; int blocksize, result; + /* + * We do a pretty difficult piece of bootstrap by reading the + * MFT (and other metadata) from disk into memory. We'll only + * release this metadata during umount, so the locking patterns + * observed during bootstrap do not count. So turn off the + * observation of locking patterns (strictly for this context + * only) while mounting NTFS. [The validator is still active + * otherwise, even for this context: it will for example record + * lock class registrations.] + */ + lockdep_off(); ntfs_debug("Entering."); #ifndef NTFS_RW sb->s_flags |= MS_RDONLY; @@ -2754,6 +2782,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) if (!silent) ntfs_error(sb, "Allocation of NTFS volume structure " "failed. Aborting mount..."); + lockdep_on(); return -ENOMEM; } /* Initialize ntfs_volume structure. */ @@ -2940,6 +2969,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) mutex_unlock(&ntfs_lock); sb->s_export_op = &ntfs_export_ops; lock_kernel(); + lockdep_on(); return 0; } ntfs_error(sb, "Failed to allocate root directory."); @@ -3059,6 +3089,7 @@ err_out_now: sb->s_fs_info = NULL; kfree(vol); ntfs_debug("Failed, returning -EINVAL."); + lockdep_on(); return -EINVAL; } diff --git a/fs/ntfs/sysctl.h b/fs/ntfs/sysctl.h index c8064cae8f1..beda5bf9640 100644 --- a/fs/ntfs/sysctl.h +++ b/fs/ntfs/sysctl.h @@ -24,7 +24,6 @@ #ifndef _LINUX_NTFS_SYSCTL_H #define _LINUX_NTFS_SYSCTL_H -#include <linux/config.h> #if defined(DEBUG) && defined(CONFIG_SYSCTL) diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 47152bf9a7f..f1d1c342ce0 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -558,16 +558,9 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, u64 vbo_max; /* file offset, max_blocks from iblock */ u64 p_blkno; int contig_blocks; - unsigned char blocksize_bits; + unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; - if (!inode || !bh_result) { - mlog(ML_ERROR, "inode or bh_result is null\n"); - return -EIO; - } - - blocksize_bits = inode->i_sb->s_blocksize_bits; - /* This function won't even be called if the request isn't all * nicely aligned and of the right size, so there's no need * for us to check any of that. */ @@ -666,7 +659,7 @@ out: return ret; } -struct address_space_operations ocfs2_aops = { +const struct address_space_operations ocfs2_aops = { .readpage = ocfs2_readpage, .writepage = ocfs2_writepage, .prepare_write = ocfs2_prepare_write, diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 1d26cfcd9f8..504595d6cf6 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -517,6 +517,7 @@ static inline void o2hb_prepare_block(struct o2hb_region *reg, hb_block->hb_seq = cpu_to_le64(cputime); hb_block->hb_node = node_num; hb_block->hb_generation = cpu_to_le64(generation); + hb_block->hb_dead_ms = cpu_to_le32(o2hb_dead_threshold * O2HB_REGION_TIMEOUT_MS); /* This step must always happen last! */ hb_block->hb_cksum = cpu_to_le32(o2hb_compute_block_crc_le(reg, @@ -645,6 +646,8 @@ static int o2hb_check_slot(struct o2hb_region *reg, struct o2nm_node *node; struct o2hb_disk_heartbeat_block *hb_block = reg->hr_tmp_block; u64 cputime; + unsigned int dead_ms = o2hb_dead_threshold * O2HB_REGION_TIMEOUT_MS; + unsigned int slot_dead_ms; memcpy(hb_block, slot->ds_raw_block, reg->hr_block_bytes); @@ -733,6 +736,23 @@ fire_callbacks: &o2hb_live_slots[slot->ds_node_num]); slot->ds_equal_samples = 0; + + /* We want to be sure that all nodes agree on the + * number of milliseconds before a node will be + * considered dead. The self-fencing timeout is + * computed from this value, and a discrepancy might + * result in heartbeat calling a node dead when it + * hasn't self-fenced yet. */ + slot_dead_ms = le32_to_cpu(hb_block->hb_dead_ms); + if (slot_dead_ms && slot_dead_ms != dead_ms) { + /* TODO: Perhaps we can fail the region here. */ + mlog(ML_ERROR, "Node %d on device %s has a dead count " + "of %u ms, but our count is %u ms.\n" + "Please double check your configuration values " + "for 'O2CB_HEARTBEAT_THRESHOLD'\n", + slot->ds_node_num, reg->hr_dev_name, slot_dead_ms, + dead_ms); + } goto out; } diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h index 73edad78253..a42628ba9dd 100644 --- a/fs/ocfs2/cluster/masklog.h +++ b/fs/ocfs2/cluster/masklog.h @@ -123,6 +123,17 @@ #define MLOG_MASK_PREFIX 0 #endif +/* + * When logging is disabled, force the bit test to 0 for anything other + * than errors and notices, allowing gcc to remove the code completely. + * When enabled, allow all masks. + */ +#if defined(CONFIG_OCFS2_DEBUG_MASKLOG) +#define ML_ALLOWED_BITS ~0 +#else +#define ML_ALLOWED_BITS (ML_ERROR|ML_NOTICE) +#endif + #define MLOG_MAX_BITS 64 struct mlog_bits { @@ -187,7 +198,8 @@ extern struct mlog_bits mlog_and_bits, mlog_not_bits; #define mlog(mask, fmt, args...) do { \ u64 __m = MLOG_MASK_PREFIX | (mask); \ - if (__mlog_test_u64(__m, mlog_and_bits) && \ + if ((__m & ML_ALLOWED_BITS) && \ + __mlog_test_u64(__m, mlog_and_bits) && \ !__mlog_test_u64(__m, mlog_not_bits)) { \ if (__m & ML_ERROR) \ __mlog_printk(KERN_ERR, "ERROR: "fmt , ##args); \ @@ -204,6 +216,7 @@ extern struct mlog_bits mlog_and_bits, mlog_not_bits; mlog(ML_ERROR, "status = %lld\n", (long long)_st); \ } while (0) +#if defined(CONFIG_OCFS2_DEBUG_MASKLOG) #define mlog_entry(fmt, args...) do { \ mlog(ML_ENTRY, "ENTRY:" fmt , ##args); \ } while (0) @@ -247,6 +260,13 @@ extern struct mlog_bits mlog_and_bits, mlog_not_bits; #define mlog_exit_void() do { \ mlog(ML_EXIT, "EXIT\n"); \ } while (0) +#else +#define mlog_entry(...) do { } while (0) +#define mlog_entry_void(...) do { } while (0) +#define mlog_exit(...) do { } while (0) +#define mlog_exit_ptr(...) do { } while (0) +#define mlog_exit_void(...) do { } while (0) +#endif /* defined(CONFIG_OCFS2_DEBUG_MASKLOG) */ #define mlog_bug_on_msg(cond, fmt, args...) do { \ if (cond) { \ diff --git a/fs/ocfs2/cluster/ocfs2_heartbeat.h b/fs/ocfs2/cluster/ocfs2_heartbeat.h index 94096069cb4..3f4151da970 100644 --- a/fs/ocfs2/cluster/ocfs2_heartbeat.h +++ b/fs/ocfs2/cluster/ocfs2_heartbeat.h @@ -32,6 +32,7 @@ struct o2hb_disk_heartbeat_block { __u8 hb_pad1[3]; __le32 hb_cksum; __le64 hb_generation; + __le32 hb_dead_ms; }; #endif /* _OCFS2_HEARTBEAT_H */ diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index 1591eb37a72..b650efa8c8b 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c @@ -396,8 +396,8 @@ static void o2net_set_nn_state(struct o2net_node *nn, } if (was_valid && !valid) { - mlog(ML_NOTICE, "no longer connected to " SC_NODEF_FMT "\n", - SC_NODEF_ARGS(old_sc)); + printk(KERN_INFO "o2net: no longer connected to " + SC_NODEF_FMT "\n", SC_NODEF_ARGS(old_sc)); o2net_complete_nodes_nsw(nn); } @@ -409,10 +409,10 @@ static void o2net_set_nn_state(struct o2net_node *nn, * the only way to start connecting again is to down * heartbeat and bring it back up. */ cancel_delayed_work(&nn->nn_connect_expired); - mlog(ML_NOTICE, "%s " SC_NODEF_FMT "\n", - o2nm_this_node() > sc->sc_node->nd_num ? - "connected to" : "accepted connection from", - SC_NODEF_ARGS(sc)); + printk(KERN_INFO "o2net: %s " SC_NODEF_FMT "\n", + o2nm_this_node() > sc->sc_node->nd_num ? + "connected to" : "accepted connection from", + SC_NODEF_ARGS(sc)); } /* trigger the connecting worker func as long as we're not valid, @@ -1280,7 +1280,7 @@ static void o2net_idle_timer(unsigned long data) do_gettimeofday(&now); - mlog(ML_NOTICE, "connection to " SC_NODEF_FMT " has been idle for 10 " + printk(KERN_INFO "o2net: connection to " SC_NODEF_FMT " has been idle for 10 " "seconds, shutting it down.\n", SC_NODEF_ARGS(sc)); mlog(ML_NOTICE, "here are some times that might help debug the " "situation: (tmr %ld.%ld now %ld.%ld dr %ld.%ld adv " diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index ae47f450792..3d494d1a5f3 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -213,11 +213,9 @@ int ocfs2_find_files_on_disk(const char *name, struct ocfs2_dir_entry **dirent) { int status = -ENOENT; - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - mlog_entry("(osb=%p, parent=%llu, name='%.*s', blkno=%p, inode=%p)\n", - osb, (unsigned long long)OCFS2_I(inode)->ip_blkno, - namelen, name, blkno, inode); + mlog_entry("(name=%.*s, blkno=%p, inode=%p, dirent_bh=%p, dirent=%p)\n", + namelen, name, blkno, inode, dirent_bh, dirent); *dirent_bh = ocfs2_find_entry(name, namelen, inode, dirent); if (!*dirent_bh || !*dirent) { diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h index 9bdc9cf6599..14530ee7e11 100644 --- a/fs/ocfs2/dlm/dlmcommon.h +++ b/fs/ocfs2/dlm/dlmcommon.h @@ -822,8 +822,6 @@ int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data); int dlm_finalize_reco_handler(struct o2net_msg *msg, u32 len, void *data); int dlm_do_master_requery(struct dlm_ctxt *dlm, struct dlm_lock_resource *res, u8 nodenum, u8 *real_master); -int dlm_lockres_master_requery(struct dlm_ctxt *dlm, - struct dlm_lock_resource *res, u8 *real_master); int dlm_dispatch_assert_master(struct dlm_ctxt *dlm, diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index b8c23f7ba67..8d1065f8b3b 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c @@ -408,12 +408,13 @@ static void __dlm_print_nodes(struct dlm_ctxt *dlm) assert_spin_locked(&dlm->spinlock); - mlog(ML_NOTICE, "Nodes in my domain (\"%s\"):\n", dlm->name); + printk(KERN_INFO "ocfs2_dlm: Nodes in domain (\"%s\"): ", dlm->name); while ((node = find_next_bit(dlm->domain_map, O2NM_MAX_NODES, node + 1)) < O2NM_MAX_NODES) { - mlog(ML_NOTICE, " node %d\n", node); + printk("%d ", node); } + printk("\n"); } static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data) @@ -429,7 +430,7 @@ static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data) node = exit_msg->node_idx; - mlog(0, "Node %u leaves domain %s\n", node, dlm->name); + printk(KERN_INFO "ocfs2_dlm: Node %u leaves domain %s\n", node, dlm->name); spin_lock(&dlm->spinlock); clear_bit(node, dlm->domain_map); @@ -678,6 +679,8 @@ static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data) set_bit(assert->node_idx, dlm->domain_map); __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN); + printk(KERN_INFO "ocfs2_dlm: Node %u joins domain %s\n", + assert->node_idx, dlm->name); __dlm_print_nodes(dlm); /* notify anything attached to the heartbeat events */ diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index 29b2845f370..594745fab0b 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -95,6 +95,9 @@ static void dlm_reco_unlock_ast(void *astdata, enum dlm_status st); static void dlm_request_all_locks_worker(struct dlm_work_item *item, void *data); static void dlm_mig_lockres_worker(struct dlm_work_item *item, void *data); +static int dlm_lockres_master_requery(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res, + u8 *real_master); static u64 dlm_get_next_mig_cookie(void); @@ -1484,8 +1487,9 @@ leave: -int dlm_lockres_master_requery(struct dlm_ctxt *dlm, - struct dlm_lock_resource *res, u8 *real_master) +static int dlm_lockres_master_requery(struct dlm_ctxt *dlm, + struct dlm_lock_resource *res, + u8 *real_master) { struct dlm_node_iter iter; int nodenum; diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 4acd37286bd..762eb1fbb34 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -2071,8 +2071,7 @@ int ocfs2_dlm_init(struct ocfs2_super *osb) } /* launch vote thread */ - osb->vote_task = kthread_run(ocfs2_vote_thread, osb, "ocfs2vote-%d", - osb->osb_id); + osb->vote_task = kthread_run(ocfs2_vote_thread, osb, "ocfs2vote"); if (IS_ERR(osb->vote_task)) { status = PTR_ERR(osb->vote_task); osb->vote_task = NULL; diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c index 1a5c69071df..fcd4475d1f8 100644 --- a/fs/ocfs2/extent_map.c +++ b/fs/ocfs2/extent_map.c @@ -298,7 +298,7 @@ static int ocfs2_extent_map_find_leaf(struct inode *inode, ret = ocfs2_extent_map_insert(inode, rec, le16_to_cpu(el->l_tree_depth)); - if (ret) { + if (ret && (ret != -EEXIST)) { mlog_errno(ret); goto out_free; } @@ -427,6 +427,11 @@ static int ocfs2_extent_map_insert_entry(struct ocfs2_extent_map *em, /* * Simple rule: on any return code other than -EAGAIN, anything left * in the insert_context will be freed. + * + * Simple rule #2: A return code of -EEXIST from this function or + * its calls to ocfs2_extent_map_insert_entry() signifies that another + * thread beat us to the insert. It is not an actual error, but it + * tells the caller we have no more work to do. */ static int ocfs2_extent_map_try_insert(struct inode *inode, struct ocfs2_extent_rec *rec, @@ -448,22 +453,32 @@ static int ocfs2_extent_map_try_insert(struct inode *inode, goto out_unlock; } + /* Since insert_entry failed, the map MUST have old_ent */ old_ent = ocfs2_extent_map_lookup(em, le32_to_cpu(rec->e_cpos), - le32_to_cpu(rec->e_clusters), NULL, - NULL); + le32_to_cpu(rec->e_clusters), + NULL, NULL); BUG_ON(!old_ent); - ret = -EEXIST; - if (old_ent->e_tree_depth < tree_depth) + if (old_ent->e_tree_depth < tree_depth) { + /* Another thread beat us to the lower tree_depth */ + ret = -EEXIST; goto out_unlock; + } if (old_ent->e_tree_depth == tree_depth) { + /* + * Another thread beat us to this tree_depth. + * Let's make sure we agree with that thread (the + * extent_rec should be identical). + */ if (!memcmp(rec, &old_ent->e_rec, sizeof(struct ocfs2_extent_rec))) ret = 0; + else + /* FIXME: Should this be ESRCH/EBADR??? */ + ret = -EEXIST; - /* FIXME: Should this be ESRCH/EBADR??? */ goto out_unlock; } @@ -599,7 +614,7 @@ static int ocfs2_extent_map_insert(struct inode *inode, tree_depth, &ctxt); } while (ret == -EAGAIN); - if (ret < 0) + if ((ret < 0) && (ret != -EEXIST)) mlog_errno(ret); if (ctxt.left_ent) diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h index 84c50796128..35140f6cf84 100644 --- a/fs/ocfs2/inode.h +++ b/fs/ocfs2/inode.h @@ -114,7 +114,7 @@ static inline struct ocfs2_inode_info *OCFS2_I(struct inode *inode) extern kmem_cache_t *ocfs2_inode_cache; -extern struct address_space_operations ocfs2_aops; +extern const struct address_space_operations ocfs2_aops; struct buffer_head *ocfs2_bread(struct inode *inode, int block, int *err, int reada); diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 910a601b2e9..f92bf1dd379 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -784,8 +784,7 @@ int ocfs2_journal_load(struct ocfs2_journal *journal) } /* Launch the commit thread */ - osb->commit_task = kthread_run(ocfs2_commit_thread, osb, "ocfs2cmt-%d", - osb->osb_id); + osb->commit_task = kthread_run(ocfs2_commit_thread, osb, "ocfs2cmt"); if (IS_ERR(osb->commit_task)) { status = PTR_ERR(osb->commit_task); osb->commit_task = NULL; @@ -1118,7 +1117,7 @@ void ocfs2_recovery_thread(struct ocfs2_super *osb, int node_num) goto out; osb->recovery_thread_task = kthread_run(__ocfs2_recovery_thread, osb, - "ocfs2rec-%d", osb->osb_id); + "ocfs2rec"); if (IS_ERR(osb->recovery_thread_task)) { mlog_errno((int)PTR_ERR(osb->recovery_thread_task)); osb->recovery_thread_task = NULL; diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c index 843cf9ddefe..83934e33e5b 100644 --- a/fs/ocfs2/mmap.c +++ b/fs/ocfs2/mmap.c @@ -46,12 +46,12 @@ static struct page *ocfs2_nopage(struct vm_area_struct * area, unsigned long address, int *type) { - struct inode *inode = area->vm_file->f_dentry->d_inode; struct page *page = NOPAGE_SIGBUS; sigset_t blocked, oldset; int ret; - mlog_entry("(inode %lu, address %lu)\n", inode->i_ino, address); + mlog_entry("(area=%p, address=%lu, type=%p)\n", area, address, + type); /* The best way to deal with signals in this path is * to block them upfront, rather than allowing the diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index da1093039c0..cd4a6f253d1 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -184,7 +184,6 @@ struct ocfs2_journal; struct ocfs2_journal_handle; struct ocfs2_super { - u32 osb_id; /* id used by the proc interface */ struct task_struct *commit_task; struct super_block *sb; struct inode *root_inode; @@ -222,13 +221,11 @@ struct ocfs2_super unsigned long s_mount_opt; u16 max_slots; - u16 num_nodes; s16 node_num; s16 slot_num; int s_sectsize_bits; int s_clustersize; int s_clustersize_bits; - struct proc_dir_entry *proc_sub_dir; /* points to /proc/fs/ocfs2/<maj_min> */ atomic_t vol_state; struct mutex recovery_lock; @@ -294,7 +291,6 @@ struct ocfs2_super }; #define OCFS2_SB(sb) ((struct ocfs2_super *)(sb)->s_fs_info) -#define OCFS2_MAX_OSB_ID 65536 static inline int ocfs2_should_order_data(struct inode *inode) { diff --git a/fs/ocfs2/slot_map.c b/fs/ocfs2/slot_map.c index 871627961d6..aa6f5aadedc 100644 --- a/fs/ocfs2/slot_map.c +++ b/fs/ocfs2/slot_map.c @@ -264,7 +264,7 @@ int ocfs2_find_slot(struct ocfs2_super *osb) osb->slot_num = slot; spin_unlock(&si->si_lock); - mlog(ML_NOTICE, "taking node slot %d\n", osb->slot_num); + mlog(0, "taking node slot %d\n", osb->slot_num); status = ocfs2_update_disk_slots(osb, si); if (status < 0) diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index cdf73393f09..382706a67ff 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -68,13 +68,6 @@ #include "buffer_head_io.h" -/* - * Globals - */ -static spinlock_t ocfs2_globals_lock = SPIN_LOCK_UNLOCKED; - -static u32 osb_id; /* Keeps track of next available OSB Id */ - static kmem_cache_t *ocfs2_inode_cachep = NULL; kmem_cache_t *ocfs2_lock_cache = NULL; @@ -642,10 +635,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) ocfs2_complete_mount_recovery(osb); - printk("ocfs2: Mounting device (%u,%u) on (node %d, slot %d) with %s " - "data mode.\n", - MAJOR(sb->s_dev), MINOR(sb->s_dev), osb->node_num, - osb->slot_num, + printk(KERN_INFO "ocfs2: Mounting device (%s) on (node %d, slot %d) " + "with %s data mode.\n", + osb->dev_str, osb->node_num, osb->slot_num, osb->s_mount_opt & OCFS2_MOUNT_DATA_WRITEBACK ? "writeback" : "ordered"); @@ -800,10 +792,6 @@ static int __init ocfs2_init(void) goto leave; } - spin_lock(&ocfs2_globals_lock); - osb_id = 0; - spin_unlock(&ocfs2_globals_lock); - ocfs2_debugfs_root = debugfs_create_dir("ocfs2", NULL); if (!ocfs2_debugfs_root) { status = -EFAULT; @@ -1020,7 +1008,7 @@ static int ocfs2_fill_local_node_info(struct ocfs2_super *osb) goto bail; } - mlog(ML_NOTICE, "I am node %d\n", osb->node_num); + mlog(0, "I am node %d\n", osb->node_num); status = 0; bail: @@ -1191,8 +1179,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) atomic_set(&osb->vol_state, VOLUME_DISMOUNTED); - printk("ocfs2: Unmounting device (%u,%u) on (node %d)\n", - MAJOR(osb->sb->s_dev), MINOR(osb->sb->s_dev), osb->node_num); + printk(KERN_INFO "ocfs2: Unmounting device (%s) on (node %d)\n", + osb->dev_str, osb->node_num); ocfs2_delete_osb(osb); kfree(osb); @@ -1212,8 +1200,6 @@ static int ocfs2_setup_osb_uuid(struct ocfs2_super *osb, const unsigned char *uu if (osb->uuid_str == NULL) return -ENOMEM; - memcpy(osb->uuid, uuid, OCFS2_VOL_UUID_LEN); - for (i = 0, ptr = osb->uuid_str; i < OCFS2_VOL_UUID_LEN; i++) { /* print with null */ ret = snprintf(ptr, 3, "%02X", uuid[i]); @@ -1311,13 +1297,6 @@ static int ocfs2_initialize_super(struct super_block *sb, goto bail; } - osb->uuid = kmalloc(OCFS2_VOL_UUID_LEN, GFP_KERNEL); - if (!osb->uuid) { - mlog(ML_ERROR, "unable to alloc uuid\n"); - status = -ENOMEM; - goto bail; - } - di = (struct ocfs2_dinode *)bh->b_data; osb->max_slots = le16_to_cpu(di->id2.i_super.s_max_slots); @@ -1327,7 +1306,7 @@ static int ocfs2_initialize_super(struct super_block *sb, status = -EINVAL; goto bail; } - mlog(ML_NOTICE, "max_slots for this device: %u\n", osb->max_slots); + mlog(0, "max_slots for this device: %u\n", osb->max_slots); init_waitqueue_head(&osb->osb_wipe_event); osb->osb_orphan_wipes = kcalloc(osb->max_slots, @@ -1418,7 +1397,7 @@ static int ocfs2_initialize_super(struct super_block *sb, goto bail; } - memcpy(&uuid_net_key, &osb->uuid[i], sizeof(osb->net_key)); + memcpy(&uuid_net_key, di->id2.i_super.s_uuid, sizeof(uuid_net_key)); osb->net_key = le32_to_cpu(uuid_net_key); strncpy(osb->vol_label, di->id2.i_super.s_label, 63); @@ -1484,18 +1463,6 @@ static int ocfs2_initialize_super(struct super_block *sb, goto bail; } - /* Link this osb onto the global linked list of all osb structures. */ - /* The Global Link List is mainted for the whole driver . */ - spin_lock(&ocfs2_globals_lock); - osb->osb_id = osb_id; - if (osb_id < OCFS2_MAX_OSB_ID) - osb_id++; - else { - mlog(ML_ERROR, "Too many volumes mounted\n"); - status = -ENOMEM; - } - spin_unlock(&ocfs2_globals_lock); - bail: mlog_exit(status); return status; diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c index 0c8a1294ec9..c0f68aa6c17 100644 --- a/fs/ocfs2/symlink.c +++ b/fs/ocfs2/symlink.c @@ -154,7 +154,7 @@ static void *ocfs2_follow_link(struct dentry *dentry, } status = vfs_follow_link(nd, link); - if (status) + if (status && status != -ENOENT) mlog_errno(status); bail: if (page) { diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile index 42c7d3878ed..d713ce6b3e1 100644 --- a/fs/partitions/Makefile +++ b/fs/partitions/Makefile @@ -4,7 +4,6 @@ obj-y := check.o -obj-$(CONFIG_DEVFS_FS) += devfs.o obj-$(CONFIG_ACORN_PARTITION) += acorn.o obj-$(CONFIG_AMIGA_PARTITION) += amiga.o obj-$(CONFIG_ATARI_PARTITION) += atari.o diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c index c05085710fc..1bc9f372c7d 100644 --- a/fs/partitions/acorn.c +++ b/fs/partitions/acorn.c @@ -12,7 +12,6 @@ * every single manufacturer of SCSI and IDE cards created their own * method. */ -#include <linux/config.h> #include <linux/buffer_head.h> #include <linux/adfs_fs.h> diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 2ef313a96b6..839634026eb 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -18,10 +18,8 @@ #include <linux/fs.h> #include <linux/kmod.h> #include <linux/ctype.h> -#include <linux/devfs_fs_kernel.h> #include "check.h" -#include "devfs.h" #include "acorn.h" #include "amiga.h" @@ -161,18 +159,11 @@ check_partition(struct gendisk *hd, struct block_device *bdev) if (!state) return NULL; -#ifdef CONFIG_DEVFS_FS - if (hd->devfs_name[0] != '\0') { - printk(KERN_INFO " /dev/%s:", hd->devfs_name); + disk_name(hd, 0, state->name); + printk(KERN_INFO " %s:", state->name); + if (isdigit(state->name[strlen(state->name)-1])) sprintf(state->name, "p"); - } -#endif - else { - disk_name(hd, 0, state->name); - printk(KERN_INFO " %s:", state->name); - if (isdigit(state->name[strlen(state->name)-1])) - sprintf(state->name, "p"); - } + state->limit = hd->minors; i = res = 0; while (!res && check_part[i]) { @@ -328,7 +319,6 @@ void delete_partition(struct gendisk *disk, int part) p->nr_sects = 0; p->ios[0] = p->ios[1] = 0; p->sectors[0] = p->sectors[1] = 0; - devfs_remove("%s/part%d", disk->devfs_name, part); sysfs_remove_link(&p->kobj, "subsystem"); if (p->holder_dir) kobject_unregister(p->holder_dir); @@ -350,10 +340,6 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) p->nr_sects = len; p->partno = part; - devfs_mk_bdev(MKDEV(disk->major, disk->first_minor + part), - S_IFBLK|S_IRUSR|S_IWUSR, - "%s/part%d", disk->devfs_name, part); - if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1])) snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part); else @@ -423,14 +409,8 @@ void register_disk(struct gendisk *disk) disk_sysfs_add_subdirs(disk); /* No minors to use for partitions */ - if (disk->minors == 1) { - if (disk->devfs_name[0] != '\0') - devfs_add_disk(disk); + if (disk->minors == 1) goto exit; - } - - /* always add handle for the whole disk */ - devfs_add_partitioned(disk); /* No such device (e.g., media were just removed) */ if (!get_capacity(disk)) @@ -538,8 +518,6 @@ void del_gendisk(struct gendisk *disk) disk_stat_set_all(disk, 0); disk->stamp = 0; - devfs_remove_disk(disk); - kobject_uevent(&disk->kobj, KOBJ_REMOVE); if (disk->holder_dir) kobject_unregister(disk->holder_dir); diff --git a/fs/partitions/devfs.c b/fs/partitions/devfs.c deleted file mode 100644 index 3f0a780c9ce..00000000000 --- a/fs/partitions/devfs.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This tries to keep block devices away from devfs as much as possible. - */ -#include <linux/fs.h> -#include <linux/devfs_fs_kernel.h> -#include <linux/vmalloc.h> -#include <linux/genhd.h> -#include <linux/bitops.h> -#include <linux/mutex.h> - - -struct unique_numspace { - u32 num_free; /* Num free in bits */ - u32 length; /* Array length in bytes */ - unsigned long *bits; - struct semaphore mutex; -}; - -static DEFINE_MUTEX(numspace_mutex); - -static int expand_numspace(struct unique_numspace *s) -{ - u32 length; - void *bits; - - if (s->length < 16) - length = 16; - else - length = s->length << 1; - - bits = vmalloc(length); - if (!bits) - return -ENOMEM; - if (s->bits) { - memcpy(bits, s->bits, s->length); - vfree(s->bits); - } - - s->num_free = (length - s->length) << 3; - s->bits = bits; - memset(bits + s->length, 0, length - s->length); - s->length = length; - - return 0; -} - -static int alloc_unique_number(struct unique_numspace *s) -{ - int rval = 0; - - mutex_lock(&numspace_mutex); - if (s->num_free < 1) - rval = expand_numspace(s); - if (!rval) { - rval = find_first_zero_bit(s->bits, s->length << 3); - --s->num_free; - __set_bit(rval, s->bits); - } - mutex_unlock(&numspace_mutex); - - return rval; -} - -static void dealloc_unique_number(struct unique_numspace *s, int number) -{ - int old_val; - - if (number >= 0) { - mutex_lock(&numspace_mutex); - old_val = __test_and_clear_bit(number, s->bits); - if (old_val) - ++s->num_free; - mutex_unlock(&numspace_mutex); - } -} - -static struct unique_numspace disc_numspace; -static struct unique_numspace cdrom_numspace; - -void devfs_add_partitioned(struct gendisk *disk) -{ - char dirname[64], symlink[16]; - - devfs_mk_dir(disk->devfs_name); - devfs_mk_bdev(MKDEV(disk->major, disk->first_minor), - S_IFBLK|S_IRUSR|S_IWUSR, - "%s/disc", disk->devfs_name); - - disk->number = alloc_unique_number(&disc_numspace); - - sprintf(symlink, "discs/disc%d", disk->number); - sprintf(dirname, "../%s", disk->devfs_name); - devfs_mk_symlink(symlink, dirname); - -} - -void devfs_add_disk(struct gendisk *disk) -{ - devfs_mk_bdev(MKDEV(disk->major, disk->first_minor), - (disk->flags & GENHD_FL_CD) ? - S_IFBLK|S_IRUGO|S_IWUGO : - S_IFBLK|S_IRUSR|S_IWUSR, - "%s", disk->devfs_name); - - if (disk->flags & GENHD_FL_CD) { - char dirname[64], symlink[16]; - - disk->number = alloc_unique_number(&cdrom_numspace); - - sprintf(symlink, "cdroms/cdrom%d", disk->number); - sprintf(dirname, "../%s", disk->devfs_name); - devfs_mk_symlink(symlink, dirname); - } -} - -void devfs_remove_disk(struct gendisk *disk) -{ - if (disk->minors != 1) { - devfs_remove("discs/disc%d", disk->number); - dealloc_unique_number(&disc_numspace, disk->number); - devfs_remove("%s/disc", disk->devfs_name); - } - if (disk->flags & GENHD_FL_CD) { - devfs_remove("cdroms/cdrom%d", disk->number); - dealloc_unique_number(&cdrom_numspace, disk->number); - } - devfs_remove(disk->devfs_name); -} - - diff --git a/fs/partitions/devfs.h b/fs/partitions/devfs.h deleted file mode 100644 index 176118b4e49..00000000000 --- a/fs/partitions/devfs.h +++ /dev/null @@ -1,10 +0,0 @@ - -#ifdef CONFIG_DEVFS_FS -void devfs_add_disk(struct gendisk *dev); -void devfs_add_partitioned(struct gendisk *dev); -void devfs_remove_disk(struct gendisk *dev); -#else -# define devfs_add_disk(disk) do { } while (0) -# define devfs_add_partitioned(disk) do { } while (0) -# define devfs_remove_disk(disk) do { } while (0) -#endif diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c index 0f5b017aeba..63730282ad8 100644 --- a/fs/partitions/efi.c +++ b/fs/partitions/efi.c @@ -91,7 +91,6 @@ * - Code works, detects all the partitions. * ************************************************************/ -#include <linux/config.h> #include <linux/crc32.h> #include "check.h" #include "efi.h" diff --git a/fs/partitions/efi.h b/fs/partitions/efi.h index c44fb056144..2cc89d0475b 100644 --- a/fs/partitions/efi.h +++ b/fs/partitions/efi.h @@ -26,7 +26,6 @@ #define FS_PART_EFI_H_INCLUDED #include <linux/types.h> -#include <linux/config.h> #include <linux/fs.h> #include <linux/genhd.h> #include <linux/kernel.h> diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c index 830c55d86ab..d352a7381fe 100644 --- a/fs/partitions/ibm.c +++ b/fs/partitions/ibm.c @@ -6,7 +6,6 @@ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 */ -#include <linux/config.h> #include <linux/buffer_head.h> #include <linux/hdreg.h> #include <linux/slab.h> diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c index 813292f2121..c0871002d00 100644 --- a/fs/partitions/mac.c +++ b/fs/partitions/mac.c @@ -6,7 +6,6 @@ * Re-organised Feb 1998 Russell King */ -#include <linux/config.h> #include <linux/ctype.h> #include "check.h" #include "mac.h" diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 9935d254186..8f12587c312 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -19,7 +19,6 @@ * Re-organised Feb 1998 Russell King */ -#include <linux/config.h> #include "check.h" #include "msdos.h" diff --git a/fs/proc/array.c b/fs/proc/array.c index 7a76ad57023..7495d3e2077 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -52,7 +52,6 @@ * : base.c too. */ -#include <linux/config.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/time.h> diff --git a/fs/proc/base.c b/fs/proc/base.c index 6ba7785319d..243a94af042 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -49,7 +49,6 @@ #include <asm/uaccess.h> -#include <linux/config.h> #include <linux/errno.h> #include <linux/time.h> #include <linux/proc_fs.h> diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index 17f6e8fa139..036d14d8362 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c @@ -9,7 +9,6 @@ * Safe accesses to vmalloc/direct-mapped discontiguous areas, Kanoj Sarcar <kanoj@sgi.com> */ -#include <linux/config.h> #include <linux/mm.h> #include <linux/proc_fs.h> #include <linux/user.h> diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 5c10ea15742..9f2cfc30f9c 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -26,7 +26,6 @@ #include <linux/mman.h> #include <linux/proc_fs.h> #include <linux/ioport.h> -#include <linux/config.h> #include <linux/mm.h> #include <linux/mmzone.h> #include <linux/pagemap.h> @@ -120,7 +119,6 @@ static int meminfo_read_proc(char *page, char **start, off_t off, { struct sysinfo i; int len; - struct page_state ps; unsigned long inactive; unsigned long active; unsigned long free; @@ -129,7 +127,6 @@ static int meminfo_read_proc(char *page, char **start, off_t off, struct vmalloc_info vmi; long cached; - get_page_state(&ps); get_zone_counts(&active, &inactive, &free); /* @@ -142,7 +139,8 @@ static int meminfo_read_proc(char *page, char **start, off_t off, allowed = ((totalram_pages - hugetlb_total_pages()) * sysctl_overcommit_ratio / 100) + total_swap_pages; - cached = get_page_cache_size() - total_swapcache_pages - i.bufferram; + cached = global_page_state(NR_FILE_PAGES) - + total_swapcache_pages - i.bufferram; if (cached < 0) cached = 0; @@ -167,11 +165,14 @@ static int meminfo_read_proc(char *page, char **start, off_t off, "SwapFree: %8lu kB\n" "Dirty: %8lu kB\n" "Writeback: %8lu kB\n" + "AnonPages: %8lu kB\n" "Mapped: %8lu kB\n" "Slab: %8lu kB\n" + "PageTables: %8lu kB\n" + "NFS Unstable: %8lu kB\n" + "Bounce: %8lu kB\n" "CommitLimit: %8lu kB\n" "Committed_AS: %8lu kB\n" - "PageTables: %8lu kB\n" "VmallocTotal: %8lu kB\n" "VmallocUsed: %8lu kB\n" "VmallocChunk: %8lu kB\n", @@ -188,13 +189,16 @@ static int meminfo_read_proc(char *page, char **start, off_t off, K(i.freeram-i.freehigh), K(i.totalswap), K(i.freeswap), - K(ps.nr_dirty), - K(ps.nr_writeback), - K(ps.nr_mapped), - K(ps.nr_slab), + K(global_page_state(NR_FILE_DIRTY)), + K(global_page_state(NR_WRITEBACK)), + K(global_page_state(NR_ANON_PAGES)), + K(global_page_state(NR_FILE_MAPPED)), + K(global_page_state(NR_SLAB)), + K(global_page_state(NR_PAGETABLE)), + K(global_page_state(NR_UNSTABLE_NFS)), + K(global_page_state(NR_BOUNCE)), K(allowed), K(committed), - K(ps.nr_page_table_pages), (unsigned long)VMALLOC_TOTAL >> 10, vmi.used >> 10, vmi.largest_chunk >> 10 diff --git a/fs/proc/root.c b/fs/proc/root.c index 9995356ce73..8901c65caca 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -12,7 +12,6 @@ #include <linux/time.h> #include <linux/proc_fs.h> #include <linux/stat.h> -#include <linux/config.h> #include <linux/init.h> #include <linux/module.h> #include <linux/bitops.h> diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 20d4b2237fc..d96050728c4 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c @@ -7,7 +7,6 @@ * */ -#include <linux/config.h> #include <linux/mm.h> #include <linux/proc_fs.h> #include <linux/user.h> diff --git a/fs/qnx4/bitmap.c b/fs/qnx4/bitmap.c index 46efbf52cbe..8425cf6e962 100644 --- a/fs/qnx4/bitmap.c +++ b/fs/qnx4/bitmap.c @@ -13,7 +13,6 @@ * 28-06-1998 by Frank Denis : qnx4_free_inode (to be fixed) . */ -#include <linux/config.h> #include <linux/time.h> #include <linux/fs.h> #include <linux/qnx4_fs.h> diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c index 9031948fefd..0d7103fa0df 100644 --- a/fs/qnx4/dir.c +++ b/fs/qnx4/dir.c @@ -11,7 +11,6 @@ * 20-06-1998 by Frank Denis : Linux 2.1.99+ & dcache support. */ -#include <linux/config.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/fs.h> diff --git a/fs/qnx4/fsync.c b/fs/qnx4/fsync.c index df5bc75d541..aa3b19544be 100644 --- a/fs/qnx4/fsync.c +++ b/fs/qnx4/fsync.c @@ -10,7 +10,6 @@ * 24-03-1998 by Richard Frowijn : first release. */ -#include <linux/config.h> #include <linux/errno.h> #include <linux/time.h> #include <linux/stat.h> diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 2f24c46f72a..5a903491e69 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -12,7 +12,6 @@ * 30-06-1998 by Frank Denis : first step to write inodes. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> #include <linux/string.h> @@ -450,7 +449,7 @@ static sector_t qnx4_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,qnx4_get_block); } -static struct address_space_operations qnx4_aops = { +static const struct address_space_operations qnx4_aops = { .readpage = qnx4_readpage, .writepage = qnx4_writepage, .sync_page = block_sync_page, diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c index 4af4951d7f5..c3d83f67154 100644 --- a/fs/qnx4/namei.c +++ b/fs/qnx4/namei.c @@ -12,7 +12,6 @@ * 04-07-1998 by Frank Denis : first step for rmdir/unlink. */ -#include <linux/config.h> #include <linux/time.h> #include <linux/fs.h> #include <linux/qnx4_fs.h> diff --git a/fs/qnx4/truncate.c b/fs/qnx4/truncate.c index 86563ec01b3..6437c1c3d1d 100644 --- a/fs/qnx4/truncate.c +++ b/fs/qnx4/truncate.c @@ -10,7 +10,6 @@ * 30-06-1998 by Frank DENIS : ugly filler. */ -#include <linux/config.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/fs.h> diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c index 00a933eb820..86f14cacf64 100644 --- a/fs/ramfs/file-mmu.c +++ b/fs/ramfs/file-mmu.c @@ -26,7 +26,7 @@ #include <linux/fs.h> -struct address_space_operations ramfs_aops = { +const struct address_space_operations ramfs_aops = { .readpage = simple_readpage, .prepare_write = simple_prepare_write, .commit_write = simple_commit_write diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index f443a84b98a..99fffc9e1bf 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c @@ -27,7 +27,7 @@ static int ramfs_nommu_setattr(struct dentry *, struct iattr *); -struct address_space_operations ramfs_aops = { +const struct address_space_operations ramfs_aops = { .readpage = simple_readpage, .prepare_write = simple_prepare_write, .commit_write = simple_commit_write diff --git a/fs/ramfs/internal.h b/fs/ramfs/internal.h index 313237631b4..c2bb58e7465 100644 --- a/fs/ramfs/internal.h +++ b/fs/ramfs/internal.h @@ -10,6 +10,6 @@ */ -extern struct address_space_operations ramfs_aops; +extern const struct address_space_operations ramfs_aops; extern const struct file_operations ramfs_file_operations; extern struct inode_operations ramfs_file_inode_operations; diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index 909f71e9a30..4a7dbdee1b6 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -3,7 +3,6 @@ */ /* Reiserfs block (de)allocator, bitmap-based. */ -#include <linux/config.h> #include <linux/time.h> #include <linux/reiserfs_fs.h> #include <linux/errno.h> diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c index 973c819f803..9aabcc0ccd2 100644 --- a/fs/reiserfs/dir.c +++ b/fs/reiserfs/dir.c @@ -2,7 +2,6 @@ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ -#include <linux/config.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/fs.h> diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c index b2264ba3cc5..fba304e64de 100644 --- a/fs/reiserfs/do_balan.c +++ b/fs/reiserfs/do_balan.c @@ -15,7 +15,6 @@ ** **/ -#include <linux/config.h> #include <asm/uaccess.h> #include <linux/time.h> #include <linux/reiserfs_fs.h> diff --git a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c index 5600d3d60cf..6d0e554daa9 100644 --- a/fs/reiserfs/fix_node.c +++ b/fs/reiserfs/fix_node.c @@ -34,7 +34,6 @@ ** **/ -#include <linux/config.h> #include <linux/time.h> #include <linux/string.h> #include <linux/reiserfs_fs.h> diff --git a/fs/reiserfs/ibalance.c b/fs/reiserfs/ibalance.c index 6c5a726fd34..de391a82b99 100644 --- a/fs/reiserfs/ibalance.c +++ b/fs/reiserfs/ibalance.c @@ -2,7 +2,6 @@ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ -#include <linux/config.h> #include <asm/uaccess.h> #include <linux/string.h> #include <linux/time.h> diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 9857e50f85e..12dfdcfbee3 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -2,7 +2,6 @@ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ -#include <linux/config.h> #include <linux/time.h> #include <linux/fs.h> #include <linux/reiserfs_fs.h> @@ -2933,6 +2932,11 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) } if (error) goto out; + /* + * file size is changed, ctime and mtime are + * to be updated + */ + attr->ia_valid |= (ATTR_MTIME | ATTR_CTIME); } } @@ -2996,7 +3000,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) return error; } -struct address_space_operations reiserfs_address_space_operations = { +const struct address_space_operations reiserfs_address_space_operations = { .writepage = reiserfs_writepage, .readpage = reiserfs_readpage, .readpages = reiserfs_readpages, diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 49d1a53dbef..9b3672d6936 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -34,7 +34,6 @@ ** from within kupdate, it will ignore the immediate flag */ -#include <linux/config.h> #include <asm/uaccess.h> #include <asm/system.h> diff --git a/fs/reiserfs/lbalance.c b/fs/reiserfs/lbalance.c index 2533c1f64ab..281f8061ac5 100644 --- a/fs/reiserfs/lbalance.c +++ b/fs/reiserfs/lbalance.c @@ -2,7 +2,6 @@ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ -#include <linux/config.h> #include <asm/uaccess.h> #include <linux/string.h> #include <linux/time.h> diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index 284f7852de8..c61710e49c6 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -11,7 +11,6 @@ * NO WARRANTY */ -#include <linux/config.h> #include <linux/time.h> #include <linux/bitops.h> #include <linux/reiserfs_fs.h> diff --git a/fs/reiserfs/objectid.c b/fs/reiserfs/objectid.c index f62590aa9c9..65feba4deb6 100644 --- a/fs/reiserfs/objectid.c +++ b/fs/reiserfs/objectid.c @@ -2,7 +2,6 @@ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ -#include <linux/config.h> #include <linux/string.h> #include <linux/random.h> #include <linux/time.h> diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c index 27bd3a1df2a..bc808a91eea 100644 --- a/fs/reiserfs/prints.c +++ b/fs/reiserfs/prints.c @@ -2,7 +2,6 @@ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README */ -#include <linux/config.h> #include <linux/time.h> #include <linux/fs.h> #include <linux/reiserfs_fs.h> diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c index 731688e1cfe..5d8a8cfebc7 100644 --- a/fs/reiserfs/procfs.c +++ b/fs/reiserfs/procfs.c @@ -10,7 +10,6 @@ /* $Id: procfs.c,v 1.1.8.2 2001/07/15 17:08:42 god Exp $ */ -#include <linux/config.h> #include <linux/module.h> #include <linux/time.h> #include <linux/seq_file.h> diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index d2b25e1ba6e..8b9b1312713 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -49,7 +49,6 @@ * reiserfs_insert_item */ -#include <linux/config.h> #include <linux/time.h> #include <linux/string.h> #include <linux/pagemap.h> diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 00f1321e920..5567328f104 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -11,7 +11,6 @@ * NO WARRANTY */ -#include <linux/config.h> #include <linux/module.h> #include <linux/vmalloc.h> #include <linux/time.h> @@ -2204,7 +2203,7 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type, size_t towrite = len; struct buffer_head tmp_bh, *bh; - mutex_lock(&inode->i_mutex); + mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); while (towrite > 0) { tocopy = sb->s_blocksize - offset < towrite ? sb->s_blocksize - offset : towrite; diff --git a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c index 196e971c03c..36f108fc1cf 100644 --- a/fs/reiserfs/tail_conversion.c +++ b/fs/reiserfs/tail_conversion.c @@ -2,7 +2,6 @@ * Copyright 1999 Hans Reiser, see reiserfs/README for licensing and copyright details */ -#include <linux/config.h> #include <linux/time.h> #include <linux/pagemap.h> #include <linux/buffer_head.h> diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index 283fbc6b8ee..22eed61ebf6 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -459,7 +459,7 @@ err_out: /* Mapping from our types to the kernel */ -static struct address_space_operations romfs_aops = { +static const struct address_space_operations romfs_aops = { .readpage = romfs_readpage }; diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index ed9a24d19d7..dae67048bab 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -306,7 +306,7 @@ static int smb_commit_write(struct file *file, struct page *page, return status; } -struct address_space_operations smb_file_aops = { +const struct address_space_operations smb_file_aops = { .readpage = smb_readpage, .writepage = smb_writepage, .prepare_write = smb_prepare_write, diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 506ff87c1d4..a1ed657c3c8 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -7,7 +7,6 @@ * Please add a note about your changes to smbfs in the ChangeLog file. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/time.h> #include <linux/kernel.h> diff --git a/fs/smbfs/proto.h b/fs/smbfs/proto.h index 972ed7dad38..34fb462b237 100644 --- a/fs/smbfs/proto.h +++ b/fs/smbfs/proto.h @@ -63,7 +63,7 @@ extern int smb_revalidate_inode(struct dentry *dentry); extern int smb_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); extern int smb_notify_change(struct dentry *dentry, struct iattr *attr); /* file.c */ -extern struct address_space_operations smb_file_aops; +extern const struct address_space_operations smb_file_aops; extern const struct file_operations smb_file_operations; extern struct inode_operations smb_file_inode_operations; /* ioctl.c */ diff --git a/fs/smbfs/smbiod.c b/fs/smbfs/smbiod.c index 24577e2c489..e6754044128 100644 --- a/fs/smbfs/smbiod.c +++ b/fs/smbfs/smbiod.c @@ -5,7 +5,6 @@ * Copyright (C) 2001, Urban Widmark */ -#include <linux/config.h> #include <linux/sched.h> #include <linux/kernel.h> diff --git a/fs/stat.c b/fs/stat.c index 0f282face32..3a44dcf97da 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -4,7 +4,6 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#include <linux/config.h> #include <linux/module.h> #include <linux/mm.h> #include <linux/errno.h> diff --git a/fs/super.c b/fs/super.c index 8a669f6f3f5..6d4e8174b6d 100644 --- a/fs/super.c +++ b/fs/super.c @@ -20,7 +20,6 @@ * Heavily rewritten for 'one fs - one tree' dcache architecture. AV, Mar 2000 */ -#include <linux/config.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/init.h> @@ -54,7 +53,7 @@ DEFINE_SPINLOCK(sb_lock); * Allocates and initializes a new &struct super_block. alloc_super() * returns a pointer new superblock or %NULL if allocation had failed. */ -static struct super_block *alloc_super(void) +static struct super_block *alloc_super(struct file_system_type *type) { struct super_block *s = kzalloc(sizeof(struct super_block), GFP_USER); static struct super_operations default_op; @@ -73,6 +72,13 @@ static struct super_block *alloc_super(void) INIT_LIST_HEAD(&s->s_inodes); init_rwsem(&s->s_umount); mutex_init(&s->s_lock); + lockdep_set_class(&s->s_umount, &type->s_umount_key); + /* + * The locking rules for s_lock are up to the + * filesystem. For example ext3fs has different + * lock ordering than usbfs: + */ + lockdep_set_class(&s->s_lock, &type->s_lock_key); down_write(&s->s_umount); s->s_count = S_BIAS; atomic_set(&s->s_active, 1); @@ -296,7 +302,7 @@ retry: } if (!s) { spin_unlock(&sb_lock); - s = alloc_super(); + s = alloc_super(type); if (!s) return ERR_PTR(-ENOMEM); goto retry; diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index f0b347bd12c..5e0e31cc46f 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -16,7 +16,7 @@ extern struct super_block * sysfs_sb; -static struct address_space_operations sysfs_aops = { +static const struct address_space_operations sysfs_aops = { .readpage = simple_readpage, .prepare_write = simple_prepare_write, .commit_write = simple_commit_write diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c index 86f5f8d43d0..f2bcccd1d6f 100644 --- a/fs/sysv/itree.c +++ b/fs/sysv/itree.c @@ -465,7 +465,7 @@ static sector_t sysv_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,get_block); } -struct address_space_operations sysv_aops = { +const struct address_space_operations sysv_aops = { .readpage = sysv_readpage, .writepage = sysv_writepage, .sync_page = block_sync_page, diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h index 393a480e4de..9dcc8212093 100644 --- a/fs/sysv/sysv.h +++ b/fs/sysv/sysv.h @@ -161,7 +161,7 @@ extern struct inode_operations sysv_dir_inode_operations; extern struct inode_operations sysv_fast_symlink_inode_operations; extern const struct file_operations sysv_file_operations; extern const struct file_operations sysv_dir_operations; -extern struct address_space_operations sysv_aops; +extern const struct address_space_operations sysv_aops; extern struct super_operations sysv_sops; extern struct dentry_operations sysv_dentry_operations; diff --git a/fs/udf/file.c b/fs/udf/file.c index e34b00e303f..a59e5f33daf 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -95,7 +95,7 @@ static int udf_adinicb_commit_write(struct file *file, struct page *page, unsign return 0; } -struct address_space_operations udf_adinicb_aops = { +const struct address_space_operations udf_adinicb_aops = { .readpage = udf_adinicb_readpage, .writepage = udf_adinicb_writepage, .sync_page = block_sync_page, diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 2983afd5e7f..605f5111b6d 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -132,7 +132,7 @@ static sector_t udf_bmap(struct address_space *mapping, sector_t block) return generic_block_bmap(mapping,block,udf_get_block); } -struct address_space_operations udf_aops = { +const struct address_space_operations udf_aops = { .readpage = udf_readpage, .writepage = udf_writepage, .sync_page = block_sync_page, diff --git a/fs/udf/super.c b/fs/udf/super.c index 44fe2cb0bbb..4df822c881b 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -40,7 +40,6 @@ #include "udfdecl.h" -#include <linux/config.h> #include <linux/blkdev.h> #include <linux/slab.h> #include <linux/kernel.h> diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c index 674bb40edc8..ba068a78656 100644 --- a/fs/udf/symlink.c +++ b/fs/udf/symlink.c @@ -113,6 +113,6 @@ out: /* * symlinks can't do much... */ -struct address_space_operations udf_symlink_aops = { +const struct address_space_operations udf_symlink_aops = { .readpage = udf_symlink_filler, }; diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 023e19ba5a2..1033b7cf293 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -6,7 +6,6 @@ #include "osta_udf.h" #include <linux/fs.h> -#include <linux/config.h> #include <linux/types.h> #include <linux/udf_fs_i.h> #include <linux/udf_fs_sb.h> @@ -47,9 +46,9 @@ extern struct inode_operations udf_dir_inode_operations; extern const struct file_operations udf_dir_operations; extern struct inode_operations udf_file_inode_operations; extern const struct file_operations udf_file_operations; -extern struct address_space_operations udf_aops; -extern struct address_space_operations udf_adinicb_aops; -extern struct address_space_operations udf_symlink_aops; +extern const struct address_space_operations udf_aops; +extern const struct address_space_operations udf_adinicb_aops; +extern const struct address_space_operations udf_symlink_aops; struct udf_fileident_bh { diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 95b878e5c7a..b01804baa12 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -217,48 +217,6 @@ failed: return; } -static struct page *ufs_get_locked_page(struct address_space *mapping, - unsigned long index) -{ - struct page *page; - -try_again: - page = find_lock_page(mapping, index); - if (!page) { - page = read_cache_page(mapping, index, - (filler_t*)mapping->a_ops->readpage, - NULL); - if (IS_ERR(page)) { - printk(KERN_ERR "ufs_change_blocknr: " - "read_cache_page error: ino %lu, index: %lu\n", - mapping->host->i_ino, index); - goto out; - } - - lock_page(page); - - if (!PageUptodate(page) || PageError(page)) { - unlock_page(page); - page_cache_release(page); - - printk(KERN_ERR "ufs_change_blocknr: " - "can not read page: ino %lu, index: %lu\n", - mapping->host->i_ino, index); - - page = ERR_PTR(-EIO); - goto out; - } - } - - if (unlikely(!page->mapping || !page_has_buffers(page))) { - unlock_page(page); - page_cache_release(page); - goto try_again;/*we really need these buffers*/ - } -out: - return page; -} - /* * Modify inode page cache in such way: * have - blocks with b_blocknr equal to oldb...oldb+count-1 @@ -311,10 +269,8 @@ static void ufs_change_blocknr(struct inode *inode, unsigned int baseblk, set_page_dirty(page); - if (likely(cur_index != index)) { - unlock_page(page); - page_cache_release(page); - } + if (likely(cur_index != index)) + ufs_put_locked_page(page); } UFSD("EXIT\n"); } diff --git a/fs/ufs/file.c b/fs/ufs/file.c index 0e5001512a9..a9c6e5f04fa 100644 --- a/fs/ufs/file.c +++ b/fs/ufs/file.c @@ -60,7 +60,3 @@ const struct file_operations ufs_file_operations = { .fsync = ufs_sync_file, .sendfile = generic_file_sendfile, }; - -struct inode_operations ufs_file_inode_operations = { - .truncate = ufs_truncate, -}; diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 259bd196099..e7c8615beb6 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -98,7 +98,9 @@ static u64 ufs_frag_map(struct inode *inode, sector_t frag) u64 temp = 0L; UFSD(": frag = %llu depth = %d\n", (unsigned long long)frag, depth); - UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",uspi->s_fpbshift,uspi->s_apbmask,mask); + UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n", + uspi->s_fpbshift, uspi->s_apbmask, + (unsigned long long)mask); if (depth == 0) return 0; @@ -429,7 +431,7 @@ int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head if (!create) { phys64 = ufs_frag_map(inode, fragment); - UFSD("phys64 = %llu \n",phys64); + UFSD("phys64 = %llu\n", (unsigned long long)phys64); if (phys64) map_bh(bh_result, sb, phys64); return 0; @@ -574,7 +576,7 @@ static sector_t ufs_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,ufs_getfrag_block); } -struct address_space_operations ufs_aops = { +const struct address_space_operations ufs_aops = { .readpage = ufs_readpage, .writepage = ufs_writepage, .sync_page = block_sync_page, @@ -841,14 +843,17 @@ int ufs_sync_inode (struct inode *inode) void ufs_delete_inode (struct inode * inode) { + loff_t old_i_size; + truncate_inode_pages(&inode->i_data, 0); /*UFS_I(inode)->i_dtime = CURRENT_TIME;*/ lock_kernel(); mark_inode_dirty(inode); ufs_update_inode(inode, IS_SYNC(inode)); + old_i_size = inode->i_size; inode->i_size = 0; - if (inode->i_blocks) - ufs_truncate (inode); + if (inode->i_blocks && ufs_truncate(inode, old_i_size)) + ufs_warning(inode->i_sb, __FUNCTION__, "ufs_truncate failed\n"); ufs_free_inode (inode); unlock_kernel(); } diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 74ef5e9bedf..992ee0b87cc 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -64,7 +64,6 @@ */ -#include <linux/config.h> #include <linux/module.h> #include <linux/bitops.h> @@ -1327,7 +1326,7 @@ static ssize_t ufs_quota_write(struct super_block *sb, int type, size_t towrite = len; struct buffer_head *bh; - mutex_lock(&inode->i_mutex); + mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); while (towrite > 0) { tocopy = sb->s_blocksize - offset < towrite ? sb->s_blocksize - offset : towrite; diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 3c3b301f870..c9b55872079 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -369,24 +369,97 @@ static int ufs_trunc_tindirect (struct inode * inode) UFSD("EXIT\n"); return retry; } - -void ufs_truncate (struct inode * inode) + +static int ufs_alloc_lastblock(struct inode *inode) { + int err = 0; + struct address_space *mapping = inode->i_mapping; + struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi; struct ufs_inode_info *ufsi = UFS_I(inode); - struct super_block * sb; - struct ufs_sb_private_info * uspi; - int retry; + unsigned lastfrag, i, end; + struct page *lastpage; + struct buffer_head *bh; + + lastfrag = (i_size_read(inode) + uspi->s_fsize - 1) >> uspi->s_fshift; + + if (!lastfrag) { + ufsi->i_lastfrag = 0; + goto out; + } + lastfrag--; + + lastpage = ufs_get_locked_page(mapping, lastfrag >> + (PAGE_CACHE_SHIFT - inode->i_blkbits)); + if (IS_ERR(lastpage)) { + err = -EIO; + goto out; + } + + end = lastfrag & ((1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1); + bh = page_buffers(lastpage); + for (i = 0; i < end; ++i) + bh = bh->b_this_page; + + if (!buffer_mapped(bh)) { + err = ufs_getfrag_block(inode, lastfrag, bh, 1); + + if (unlikely(err)) + goto out_unlock; + + if (buffer_new(bh)) { + clear_buffer_new(bh); + unmap_underlying_metadata(bh->b_bdev, + bh->b_blocknr); + /* + * we do not zeroize fragment, because of + * if it maped to hole, it already contains zeroes + */ + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + set_page_dirty(lastpage); + } + } +out_unlock: + ufs_put_locked_page(lastpage); +out: + return err; +} + +int ufs_truncate(struct inode *inode, loff_t old_i_size) +{ + struct ufs_inode_info *ufsi = UFS_I(inode); + struct super_block *sb = inode->i_sb; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + int retry, err = 0; UFSD("ENTER\n"); - sb = inode->i_sb; - uspi = UFS_SB(sb)->s_uspi; - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) - return; + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return -EINVAL; if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - return; + return -EPERM; + + if (inode->i_size > old_i_size) { + /* + * if we expand file we should care about + * allocation of block for last byte first of all + */ + err = ufs_alloc_lastblock(inode); + + if (err) { + i_size_write(inode, old_i_size); + goto out; + } + /* + * go away, because of we expand file, and we do not + * need free blocks, and zeroizes page + */ + lock_kernel(); + goto almost_end; + } - block_truncate_page(inode->i_mapping, inode->i_size, ufs_getfrag_block); + block_truncate_page(inode->i_mapping, inode->i_size, ufs_getfrag_block); lock_kernel(); while (1) { @@ -404,9 +477,58 @@ void ufs_truncate (struct inode * inode) yield(); } + if (inode->i_size < old_i_size) { + /* + * now we should have enough space + * to allocate block for last byte + */ + err = ufs_alloc_lastblock(inode); + if (err) + /* + * looks like all the same - we have no space, + * but we truncate file already + */ + inode->i_size = (ufsi->i_lastfrag - 1) * uspi->s_fsize; + } +almost_end: inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; - ufsi->i_lastfrag = DIRECT_FRAGMENT; unlock_kernel(); mark_inode_dirty(inode); - UFSD("EXIT\n"); +out: + UFSD("EXIT: err %d\n", err); + return err; } + + +/* + * We don't define our `inode->i_op->truncate', and call it here, + * because of: + * - there is no way to know old size + * - there is no way inform user about error, if it happens in `truncate' + */ +static int ufs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + unsigned int ia_valid = attr->ia_valid; + int error; + + error = inode_change_ok(inode, attr); + if (error) + return error; + + if (ia_valid & ATTR_SIZE && + attr->ia_size != i_size_read(inode)) { + loff_t old_i_size = inode->i_size; + error = vmtruncate(inode, attr->ia_size); + if (error) + return error; + error = ufs_truncate(inode, old_i_size); + if (error) + return error; + } + return inode_setattr(inode, attr); +} + +struct inode_operations ufs_file_inode_operations = { + .setattr = ufs_setattr, +}; diff --git a/fs/ufs/util.c b/fs/ufs/util.c index a2f13f45708..337cf2c46d1 100644 --- a/fs/ufs/util.c +++ b/fs/ufs/util.c @@ -233,3 +233,57 @@ ufs_set_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi, dev_t dev else ufsi->i_u1.i_data[0] = fs32; } + +/** + * ufs_get_locked_page() - locate, pin and lock a pagecache page, if not exist + * read it from disk. + * @mapping: the address_space to search + * @index: the page index + * + * Locates the desired pagecache page, if not exist we'll read it, + * locks it, increments its reference + * count and returns its address. + * + */ + +struct page *ufs_get_locked_page(struct address_space *mapping, + pgoff_t index) +{ + struct page *page; + +try_again: + page = find_lock_page(mapping, index); + if (!page) { + page = read_cache_page(mapping, index, + (filler_t*)mapping->a_ops->readpage, + NULL); + if (IS_ERR(page)) { + printk(KERN_ERR "ufs_change_blocknr: " + "read_cache_page error: ino %lu, index: %lu\n", + mapping->host->i_ino, index); + goto out; + } + + lock_page(page); + + if (!PageUptodate(page) || PageError(page)) { + unlock_page(page); + page_cache_release(page); + + printk(KERN_ERR "ufs_change_blocknr: " + "can not read page: ino %lu, index: %lu\n", + mapping->host->i_ino, index); + + page = ERR_PTR(-EIO); + goto out; + } + } + + if (unlikely(!page->mapping || !page_has_buffers(page))) { + unlock_page(page); + page_cache_release(page); + goto try_again;/*we really need these buffers*/ + } +out: + return page; +} diff --git a/fs/ufs/util.h b/fs/ufs/util.h index 406981fff5e..28fce6c239b 100644 --- a/fs/ufs/util.h +++ b/fs/ufs/util.h @@ -251,6 +251,14 @@ extern void _ubh_ubhcpymem_(struct ufs_sb_private_info *, unsigned char *, struc #define ubh_memcpyubh(ubh,mem,size) _ubh_memcpyubh_(uspi,ubh,mem,size) extern void _ubh_memcpyubh_(struct ufs_sb_private_info *, struct ufs_buffer_head *, unsigned char *, unsigned); +/* This functions works with cache pages*/ +extern struct page *ufs_get_locked_page(struct address_space *mapping, + pgoff_t index); +static inline void ufs_put_locked_page(struct page *page) +{ + unlock_page(page); + page_cache_release(page); +} /* diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 3e807b828e2..c40f81ba9b1 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -1454,7 +1454,7 @@ xfs_vm_invalidatepage( block_invalidatepage(page, offset); } -struct address_space_operations xfs_address_space_operations = { +const struct address_space_operations xfs_address_space_operations = { .readpage = xfs_vm_readpage, .readpages = xfs_vm_readpages, .writepage = xfs_vm_writepage, diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/linux-2.6/xfs_aops.h index 706d8c781b8..2244e516b66 100644 --- a/fs/xfs/linux-2.6/xfs_aops.h +++ b/fs/xfs/linux-2.6/xfs_aops.h @@ -40,7 +40,7 @@ typedef struct xfs_ioend { struct work_struct io_work; /* xfsdatad work queue */ } xfs_ioend_t; -extern struct address_space_operations xfs_address_space_operations; +extern const struct address_space_operations xfs_address_space_operations; extern int xfs_get_blocks(struct inode *, sector_t, struct buffer_head *, int); #endif /* __XFS_AOPS_H__ */ diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 26fed0756f0..2af528dcfb0 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -1520,7 +1520,7 @@ xfs_mapping_buftarg( struct backing_dev_info *bdi; struct inode *inode; struct address_space *mapping; - static struct address_space_operations mapping_aops = { + static const struct address_space_operations mapping_aops = { .sync_page = block_sync_page, .migratepage = fail_migrate_page, }; diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index 4dd6592d5a4..ceda3a2859d 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -18,7 +18,6 @@ #ifndef __XFS_BUF_H__ #define __XFS_BUF_H__ -#include <linux/config.h> #include <linux/list.h> #include <linux/types.h> #include <linux/spinlock.h> diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index 601f01c92f7..270db0f3861 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -15,7 +15,6 @@ * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <linux/config.h> #include <linux/compat.h> #include <linux/init.h> #include <linux/ioctl.h> diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index 028eb17ec2e..8c021dc57d1 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h @@ -19,7 +19,6 @@ #define __XFS_LINUX__ #include <linux/types.h> -#include <linux/config.h> /* * Some types are conditional depending on the target system. |