summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2006-03-29 13:24:50 +1100
committerPaul Mackerras <paulus@samba.org>2006-03-29 13:24:50 +1100
commitbac30d1a78d0f11c613968fc8b351a91ed465386 (patch)
treee52f3c876522a2f6047a6ec1c27df2e8a79486b8 /fs
parente8222502ee6157e2713da9e0792c21f4ad458d50 (diff)
parentca9ba4471c1203bb6e759b76e83167fec54fe590 (diff)
downloadlinux-bac30d1a78d0f11c613968fc8b351a91ed465386.tar.gz
linux-bac30d1a78d0f11c613968fc8b351a91ed465386.tar.bz2
linux-bac30d1a78d0f11c613968fc8b351a91ed465386.zip
Merge ../linux-2.6
Diffstat (limited to 'fs')
-rw-r--r--fs/9p/v9fs_vfs.h4
-rw-r--r--fs/9p/vfs_dir.c2
-rw-r--r--fs/9p/vfs_file.c2
-rw-r--r--fs/adfs/adfs.h4
-rw-r--r--fs/adfs/dir.c2
-rw-r--r--fs/adfs/file.c2
-rw-r--r--fs/affs/affs.h6
-rw-r--r--fs/affs/dir.c2
-rw-r--r--fs/affs/file.c2
-rw-r--r--fs/afs/dir.c2
-rw-r--r--fs/afs/internal.h4
-rw-r--r--fs/afs/mntpt.c2
-rw-r--r--fs/afs/proc.c10
-rw-r--r--fs/autofs/autofs_i.h2
-rw-r--r--fs/autofs/dirhash.c2
-rw-r--r--fs/autofs/root.c2
-rw-r--r--fs/autofs4/autofs_i.h54
-rw-r--r--fs/autofs4/expire.c292
-rw-r--r--fs/autofs4/inode.c103
-rw-r--r--fs/autofs4/root.c328
-rw-r--r--fs/autofs4/waitq.c111
-rw-r--r--fs/bad_inode.c2
-rw-r--r--fs/befs/linuxvfs.c2
-rw-r--r--fs/bfs/bfs.h4
-rw-r--r--fs/bfs/dir.c2
-rw-r--r--fs/bfs/file.c2
-rw-r--r--fs/binfmt_misc.c6
-rw-r--r--fs/block_dev.c299
-rw-r--r--fs/buffer.c2
-rw-r--r--fs/char_dev.c6
-rw-r--r--fs/cifs/cifsfs.c10
-rw-r--r--fs/cifs/cifsfs.h10
-rw-r--r--fs/coda/dir.c2
-rw-r--r--fs/coda/file.c2
-rw-r--r--fs/coda/pioctl.c2
-rw-r--r--fs/coda/psdev.c2
-rw-r--r--fs/compat.c13
-rw-r--r--fs/configfs/configfs_internal.h6
-rw-r--r--fs/configfs/dir.c2
-rw-r--r--fs/configfs/file.c2
-rw-r--r--fs/cramfs/inode.c4
-rw-r--r--fs/debugfs/file.c4
-rw-r--r--fs/debugfs/inode.c2
-rw-r--r--fs/devfs/base.c12
-rw-r--r--fs/efs/dir.c2
-rw-r--r--fs/eventpoll.c2
-rw-r--r--fs/ext2/dir.c2
-rw-r--r--fs/ext2/ext2.h6
-rw-r--r--fs/ext2/file.c4
-rw-r--r--fs/ext3/dir.c2
-rw-r--r--fs/ext3/file.c2
-rw-r--r--fs/fat/dir.c2
-rw-r--r--fs/fat/file.c2
-rw-r--r--fs/fat/inode.c3
-rw-r--r--fs/fifo.c2
-rw-r--r--fs/file.c2
-rw-r--r--fs/freevxfs/vxfs_extern.h2
-rw-r--r--fs/freevxfs/vxfs_lookup.c2
-rw-r--r--fs/fuse/dev.c2
-rw-r--r--fs/fuse/dir.c2
-rw-r--r--fs/fuse/file.c6
-rw-r--r--fs/fuse/fuse_i.h2
-rw-r--r--fs/hfs/dir.c2
-rw-r--r--fs/hfs/hfs_fs.h2
-rw-r--r--fs/hfs/inode.c4
-rw-r--r--fs/hfsplus/dir.c2
-rw-r--r--fs/hfsplus/inode.c2
-rw-r--r--fs/hostfs/hostfs_kern.c4
-rw-r--r--fs/hostfs/hostfs_user.c1
-rw-r--r--fs/hpfs/dir.c2
-rw-r--r--fs/hpfs/file.c2
-rw-r--r--fs/hpfs/hpfs_fn.h4
-rw-r--r--fs/hppfs/hppfs_kern.c4
-rw-r--r--fs/hugetlbfs/inode.c4
-rw-r--r--fs/inode.c2
-rw-r--r--fs/inotify.c2
-rw-r--r--fs/isofs/dir.c2
-rw-r--r--fs/isofs/isofs.h2
-rw-r--r--fs/jffs/inode-v23.c8
-rw-r--r--fs/jffs2/dir.c2
-rw-r--r--fs/jffs2/file.c2
-rw-r--r--fs/jffs2/os-linux.h4
-rw-r--r--fs/jfs/file.c2
-rw-r--r--fs/jfs/jfs_inode.h4
-rw-r--r--fs/jfs/namei.c2
-rw-r--r--fs/libfs.c2
-rw-r--r--fs/mbcache.c2
-rw-r--r--fs/minix/dir.c2
-rw-r--r--fs/minix/file.c2
-rw-r--r--fs/minix/minix.h4
-rw-r--r--fs/namei.c39
-rw-r--r--fs/namespace.c8
-rw-r--r--fs/ncpfs/dir.c2
-rw-r--r--fs/ncpfs/file.c2
-rw-r--r--fs/nfs/dir.c2
-rw-r--r--fs/nfs/file.c2
-rw-r--r--fs/nfsd/export.c368
-rw-r--r--fs/nfsd/nfs4idmap.c146
-rw-r--r--fs/nfsd/nfsctl.c4
-rw-r--r--fs/nfsd/nfsfh.c2
-rw-r--r--fs/nfsd/stats.c2
-rw-r--r--fs/nfsd/vfs.c2
-rw-r--r--fs/ntfs/dir.c2
-rw-r--r--fs/ntfs/file.c4
-rw-r--r--fs/ntfs/ntfs.h6
-rw-r--r--fs/ocfs2/dlmglue.c2
-rw-r--r--fs/ocfs2/file.c4
-rw-r--r--fs/ocfs2/file.h4
-rw-r--r--fs/openpromfs/inode.c6
-rw-r--r--fs/partitions/check.c27
-rw-r--r--fs/pipe.c6
-rw-r--r--fs/proc/generic.c2
-rw-r--r--fs/proc/internal.h2
-rw-r--r--fs/proc/kcore.c2
-rw-r--r--fs/proc/kmsg.c2
-rw-r--r--fs/proc/proc_misc.c4
-rw-r--r--fs/proc/vmcore.c2
-rw-r--r--fs/qnx4/dir.c2
-rw-r--r--fs/qnx4/file.c2
-rw-r--r--fs/ramfs/file-mmu.c2
-rw-r--r--fs/ramfs/file-nommu.c2
-rw-r--r--fs/ramfs/internal.h2
-rw-r--r--fs/read_write.c2
-rw-r--r--fs/reiserfs/dir.c2
-rw-r--r--fs/reiserfs/file.c2
-rw-r--r--fs/reiserfs/procfs.c2
-rw-r--r--fs/romfs/inode.c2
-rw-r--r--fs/select.c118
-rw-r--r--fs/smbfs/dir.c2
-rw-r--r--fs/smbfs/file.c2
-rw-r--r--fs/smbfs/proto.h4
-rw-r--r--fs/sysfs/bin.c2
-rw-r--r--fs/sysfs/dir.c2
-rw-r--r--fs/sysfs/file.c2
-rw-r--r--fs/sysfs/sysfs.h6
-rw-r--r--fs/sysv/dir.c2
-rw-r--r--fs/sysv/file.c2
-rw-r--r--fs/sysv/sysv.h4
-rw-r--r--fs/udf/dir.c2
-rw-r--r--fs/udf/file.c2
-rw-r--r--fs/udf/udfdecl.h4
-rw-r--r--fs/ufs/dir.c2
-rw-r--r--fs/ufs/file.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_file.c6
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.h6
145 files changed, 1549 insertions, 755 deletions
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 43c9f7de0314..f867b8d3e973 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -39,8 +39,8 @@
extern struct file_system_type v9fs_fs_type;
extern struct address_space_operations v9fs_addr_operations;
-extern struct file_operations v9fs_file_operations;
-extern struct file_operations v9fs_dir_operations;
+extern const struct file_operations v9fs_file_operations;
+extern const struct file_operations v9fs_dir_operations;
extern struct dentry_operations v9fs_dentry_operations;
struct inode *v9fs_get_inode(struct super_block *sb, int mode);
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 766f11f1215c..e32d5971039b 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -204,7 +204,7 @@ int v9fs_dir_release(struct inode *inode, struct file *filp)
return 0;
}
-struct file_operations v9fs_dir_operations = {
+const struct file_operations v9fs_dir_operations = {
.read = generic_read_dir,
.readdir = v9fs_dir_readdir,
.open = v9fs_file_open,
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 59e744163407..083dcfcd158e 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -266,7 +266,7 @@ v9fs_file_write(struct file *filp, const char __user * data,
return total;
}
-struct file_operations v9fs_file_operations = {
+const struct file_operations v9fs_file_operations = {
.llseek = generic_file_llseek,
.read = v9fs_file_read,
.write = v9fs_file_write,
diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index f6cd01352cc8..29217ff36d44 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -85,7 +85,7 @@ void __adfs_error(struct super_block *sb, const char *function,
/* dir_*.c */
extern struct inode_operations adfs_dir_inode_operations;
-extern struct file_operations adfs_dir_operations;
+extern const struct file_operations adfs_dir_operations;
extern struct dentry_operations adfs_dentry_operations;
extern struct adfs_dir_ops adfs_f_dir_ops;
extern struct adfs_dir_ops adfs_fplus_dir_ops;
@@ -94,7 +94,7 @@ extern int adfs_dir_update(struct super_block *sb, struct object_info *obj);
/* file.c */
extern struct inode_operations adfs_file_inode_operations;
-extern struct file_operations adfs_file_operations;
+extern const struct file_operations adfs_file_operations;
static inline __u32 signed_asl(__u32 val, signed int shift)
{
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 0b4c3a028076..7b075fc397da 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -196,7 +196,7 @@ out:
return ret;
}
-struct file_operations adfs_dir_operations = {
+const struct file_operations adfs_dir_operations = {
.read = generic_read_dir,
.readdir = adfs_readdir,
.fsync = file_fsync,
diff --git a/fs/adfs/file.c b/fs/adfs/file.c
index 6af10885f9d6..1014b9f2117b 100644
--- a/fs/adfs/file.c
+++ b/fs/adfs/file.c
@@ -25,7 +25,7 @@
#include "adfs.h"
-struct file_operations adfs_file_operations = {
+const struct file_operations adfs_file_operations = {
.llseek = generic_file_llseek,
.read = generic_file_read,
.mmap = generic_file_mmap,
diff --git a/fs/affs/affs.h b/fs/affs/affs.h
index 0c6799f2137a..a43a876742b8 100644
--- a/fs/affs/affs.h
+++ b/fs/affs/affs.h
@@ -192,9 +192,9 @@ extern void affs_dir_truncate(struct inode *);
extern struct inode_operations affs_file_inode_operations;
extern struct inode_operations affs_dir_inode_operations;
extern struct inode_operations affs_symlink_inode_operations;
-extern struct file_operations affs_file_operations;
-extern struct file_operations affs_file_operations_ofs;
-extern struct file_operations affs_dir_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;
diff --git a/fs/affs/dir.c b/fs/affs/dir.c
index 548efd0ee98c..5d9649fa1814 100644
--- a/fs/affs/dir.c
+++ b/fs/affs/dir.c
@@ -17,7 +17,7 @@
static int affs_readdir(struct file *, void *, filldir_t);
-struct file_operations affs_dir_operations = {
+const struct file_operations affs_dir_operations = {
.read = generic_read_dir,
.readdir = affs_readdir,
.fsync = file_fsync,
diff --git a/fs/affs/file.c b/fs/affs/file.c
index f72fb776ecdf..7076262af39b 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -25,7 +25,7 @@ static struct buffer_head *affs_get_extblock_slow(struct inode *inode, u32 ext);
static int affs_file_open(struct inode *inode, struct file *filp);
static int affs_file_release(struct inode *inode, struct file *filp);
-struct file_operations affs_file_operations = {
+const struct file_operations affs_file_operations = {
.llseek = generic_file_llseek,
.read = generic_file_read,
.write = generic_file_write,
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 5c61c24dab2a..a6dff6a4f204 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -32,7 +32,7 @@ static int afs_d_delete(struct dentry *dentry);
static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen,
loff_t fpos, ino_t ino, unsigned dtype);
-struct file_operations afs_dir_file_operations = {
+const struct file_operations afs_dir_file_operations = {
.open = afs_dir_open,
.readdir = afs_dir_readdir,
};
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index ab8f87c66319..72febdf9a35a 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -64,7 +64,7 @@ extern struct cachefs_index_def afs_cache_cell_index_def;
* dir.c
*/
extern struct inode_operations afs_dir_inode_operations;
-extern struct file_operations afs_dir_file_operations;
+extern const struct file_operations afs_dir_file_operations;
/*
* file.c
@@ -105,7 +105,7 @@ extern struct cachefs_netfs afs_cache_netfs;
* mntpt.c
*/
extern struct inode_operations afs_mntpt_inode_operations;
-extern struct file_operations afs_mntpt_file_operations;
+extern const struct file_operations afs_mntpt_file_operations;
extern struct afs_timer afs_mntpt_expiry_timer;
extern struct afs_timer_ops afs_mntpt_expiry_timer_ops;
extern unsigned long afs_mntpt_expiry_timeout;
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 31ee06590de5..4e6eeb59b83c 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -32,7 +32,7 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir,
static int afs_mntpt_open(struct inode *inode, struct file *file);
static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd);
-struct file_operations afs_mntpt_file_operations = {
+const struct file_operations afs_mntpt_file_operations = {
.open = afs_mntpt_open,
};
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 9c81b8f7eef0..101d21b6c037 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -37,7 +37,7 @@ static struct seq_operations afs_proc_cells_ops = {
.show = afs_proc_cells_show,
};
-static struct file_operations afs_proc_cells_fops = {
+static const struct file_operations afs_proc_cells_fops = {
.open = afs_proc_cells_open,
.read = seq_read,
.write = afs_proc_cells_write,
@@ -53,7 +53,7 @@ static ssize_t afs_proc_rootcell_write(struct file *file,
const char __user *buf,
size_t size, loff_t *_pos);
-static struct file_operations afs_proc_rootcell_fops = {
+static const struct file_operations afs_proc_rootcell_fops = {
.open = afs_proc_rootcell_open,
.read = afs_proc_rootcell_read,
.write = afs_proc_rootcell_write,
@@ -77,7 +77,7 @@ static struct seq_operations afs_proc_cell_volumes_ops = {
.show = afs_proc_cell_volumes_show,
};
-static struct file_operations afs_proc_cell_volumes_fops = {
+static const struct file_operations afs_proc_cell_volumes_fops = {
.open = afs_proc_cell_volumes_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -101,7 +101,7 @@ static struct seq_operations afs_proc_cell_vlservers_ops = {
.show = afs_proc_cell_vlservers_show,
};
-static struct file_operations afs_proc_cell_vlservers_fops = {
+static const struct file_operations afs_proc_cell_vlservers_fops = {
.open = afs_proc_cell_vlservers_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -124,7 +124,7 @@ static struct seq_operations afs_proc_cell_servers_ops = {
.show = afs_proc_cell_servers_show,
};
-static struct file_operations afs_proc_cell_servers_fops = {
+static const struct file_operations afs_proc_cell_servers_fops = {
.open = afs_proc_cell_servers_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
index 990c28da5aec..a62327f1bdff 100644
--- a/fs/autofs/autofs_i.h
+++ b/fs/autofs/autofs_i.h
@@ -146,7 +146,7 @@ struct autofs_dir_ent *autofs_expire(struct super_block *,struct autofs_sb_info
extern struct inode_operations autofs_root_inode_operations;
extern struct inode_operations autofs_symlink_inode_operations;
-extern struct file_operations autofs_root_operations;
+extern const struct file_operations autofs_root_operations;
/* Initializing function */
diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c
index 5ccfcf26310d..3fded389d06b 100644
--- a/fs/autofs/dirhash.c
+++ b/fs/autofs/dirhash.c
@@ -92,7 +92,7 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
;
dput(dentry);
- if ( may_umount(mnt) == 0 ) {
+ if ( may_umount(mnt) ) {
mntput(mnt);
DPRINTK(("autofs: signaling expire on %s\n", ent->name));
return ent; /* Expirable! */
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 870e2cf33016..9cac08d6a873 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -26,7 +26,7 @@ static int autofs_root_rmdir(struct inode *,struct dentry *);
static int autofs_root_mkdir(struct inode *,struct dentry *,int);
static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
-struct file_operations autofs_root_operations = {
+const struct file_operations autofs_root_operations = {
.read = generic_read_dir,
.readdir = autofs_root_readdir,
.ioctl = autofs_root_ioctl,
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index f54c5b21f876..57c4903614e5 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -3,6 +3,7 @@
* linux/fs/autofs/autofs_i.h
*
* Copyright 1997-1998 Transmeta Corporation - All Rights Reserved
+ * Copyright 2005-2006 Ian Kent <raven@themaw.net>
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
@@ -41,14 +42,6 @@
#define AUTOFS_SUPER_MAGIC 0x0187
-/*
- * If the daemon returns a negative response (AUTOFS_IOC_FAIL) then the
- * kernel will keep the negative response cached for up to the time given
- * here, although the time can be shorter if the kernel throws the dcache
- * entry away. This probably should be settable from user space.
- */
-#define AUTOFS_NEGATIVE_TIMEOUT (60*HZ) /* 1 minute */
-
/* Unified info structure. This is pointed to by both the dentry and
inode structures. Each file in the filesystem has an instance of this
structure. It holds a reference to the dentry, so dentries are never
@@ -63,6 +56,7 @@ struct autofs_info {
struct autofs_sb_info *sbi;
unsigned long last_used;
+ atomic_t count;
mode_t mode;
size_t size;
@@ -83,23 +77,37 @@ struct autofs_wait_queue {
int hash;
int len;
char *name;
+ u32 dev;
+ u64 ino;
+ uid_t uid;
+ gid_t gid;
+ pid_t pid;
+ pid_t tgid;
/* This is for status reporting upon return */
int status;
- atomic_t notified;
+ atomic_t notify;
atomic_t wait_ctr;
};
#define AUTOFS_SBI_MAGIC 0x6d4a556d
+#define AUTOFS_TYPE_INDIRECT 0x0001
+#define AUTOFS_TYPE_DIRECT 0x0002
+#define AUTOFS_TYPE_OFFSET 0x0004
+
struct autofs_sb_info {
u32 magic;
struct dentry *root;
+ int pipefd;
struct file *pipe;
pid_t oz_pgrp;
int catatonic;
int version;
int sub_version;
+ int min_proto;
+ int max_proto;
unsigned long exp_timeout;
+ unsigned int type;
int reghost_enabled;
int needs_reghost;
struct super_block *sb;
@@ -166,8 +174,10 @@ int autofs4_expire_multi(struct super_block *, struct vfsmount *,
extern struct inode_operations autofs4_symlink_inode_operations;
extern struct inode_operations autofs4_dir_inode_operations;
extern struct inode_operations autofs4_root_inode_operations;
-extern struct file_operations autofs4_dir_operations;
-extern struct file_operations autofs4_root_operations;
+extern struct inode_operations autofs4_indirect_root_inode_operations;
+extern struct inode_operations autofs4_direct_root_inode_operations;
+extern const struct file_operations autofs4_dir_operations;
+extern const struct file_operations autofs4_root_operations;
/* Initializing function */
@@ -176,13 +186,6 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *, struct autofs_sb_info
/* Queue management functions */
-enum autofs_notify
-{
- NFY_NONE,
- NFY_MOUNT,
- NFY_EXPIRE
-};
-
int autofs4_wait(struct autofs_sb_info *,struct dentry *, enum autofs_notify);
int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int);
void autofs4_catatonic_mode(struct autofs_sb_info *);
@@ -200,12 +203,22 @@ static inline int autofs4_follow_mount(struct vfsmount **mnt, struct dentry **de
return res;
}
+static inline u32 autofs4_get_dev(struct autofs_sb_info *sbi)
+{
+ return new_encode_dev(sbi->sb->s_dev);
+}
+
+static inline u64 autofs4_get_ino(struct autofs_sb_info *sbi)
+{
+ return sbi->sb->s_root->d_inode->i_ino;
+}
+
static inline int simple_positive(struct dentry *dentry)
{
return dentry->d_inode && !d_unhashed(dentry);
}
-static inline int simple_empty_nolock(struct dentry *dentry)
+static inline int __simple_empty(struct dentry *dentry)
{
struct dentry *child;
int ret = 0;
@@ -217,3 +230,6 @@ static inline int simple_empty_nolock(struct dentry *dentry)
out:
return ret;
}
+
+void autofs4_dentry_release(struct dentry *);
+
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index dc39589df165..b8ce02607d66 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -4,7 +4,7 @@
*
* Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
* Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org>
- * Copyright 2001-2003 Ian Kent <raven@themaw.net>
+ * Copyright 2001-2006 Ian Kent <raven@themaw.net>
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
@@ -16,7 +16,7 @@
static unsigned long now;
-/* Check if a dentry can be expired return 1 if it can else return 0 */
+/* Check if a dentry can be expired */
static inline int autofs4_can_expire(struct dentry *dentry,
unsigned long timeout, int do_now)
{
@@ -41,14 +41,14 @@ static inline int autofs4_can_expire(struct dentry *dentry,
attempts if expire fails the first time */
ino->last_used = now;
}
-
return 1;
}
-/* Check a mount point for busyness return 1 if not busy, otherwise */
-static int autofs4_check_mount(struct vfsmount *mnt, struct dentry *dentry)
+/* Check a mount point for busyness */
+static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
{
- int status = 0;
+ struct dentry *top = dentry;
+ int status = 1;
DPRINTK("dentry %p %.*s",
dentry, (int)dentry->d_name.len, dentry->d_name.name);
@@ -63,9 +63,14 @@ static int autofs4_check_mount(struct vfsmount *mnt, struct dentry *dentry)
if (is_autofs4_dentry(dentry))
goto done;
- /* The big question */
- if (may_umount_tree(mnt) == 0)
- status = 1;
+ /* Update the expiry counter if fs is busy */
+ if (!may_umount_tree(mnt)) {
+ struct autofs_info *ino = autofs4_dentry_ino(top);
+ ino->last_used = jiffies;
+ goto done;
+ }
+
+ status = 0;
done:
DPRINTK("returning = %d", status);
mntput(mnt);
@@ -73,78 +78,124 @@ done:
return status;
}
+/*
+ * Calculate next entry in top down tree traversal.
+ * From next_mnt in namespace.c - elegant.
+ */
+static struct dentry *next_dentry(struct dentry *p, struct dentry *root)
+{
+ struct list_head *next = p->d_subdirs.next;
+
+ if (next == &p->d_subdirs) {
+ while (1) {
+ if (p == root)
+ return NULL;
+ next = p->d_u.d_child.next;
+ if (next != &p->d_parent->d_subdirs)
+ break;
+ p = p->d_parent;
+ }
+ }
+ return list_entry(next, struct dentry, d_u.d_child);
+}
+
+/*
+ * Check a direct mount point for busyness.
+ * Direct mounts have similar expiry semantics to tree mounts.
+ * The tree is not busy iff no mountpoints are busy and there are no
+ * autofs submounts.
+ */
+static int autofs4_direct_busy(struct vfsmount *mnt,
+ struct dentry *top,
+ unsigned long timeout,
+ int do_now)
+{
+ DPRINTK("top %p %.*s",
+ top, (int) top->d_name.len, top->d_name.name);
+
+ /* If it's busy update the expiry counters */
+ if (!may_umount_tree(mnt)) {
+ struct autofs_info *ino = autofs4_dentry_ino(top);
+ if (ino)
+ ino->last_used = jiffies;
+ return 1;
+ }
+
+ /* Timeout of a direct mount is determined by its top dentry */
+ if (!autofs4_can_expire(top, timeout, do_now))
+ return 1;
+
+ return 0;
+}
+
/* Check a directory tree of mount points for busyness
* The tree is not busy iff no mountpoints are busy
- * Return 1 if the tree is busy or 0 otherwise
*/
-static int autofs4_check_tree(struct vfsmount *mnt,
- struct dentry *top,
- unsigned long timeout,
- int do_now)
+static int autofs4_tree_busy(struct vfsmount *mnt,
+ struct dentry *top,
+ unsigned long timeout,
+ int do_now)
{
- struct dentry *this_parent = top;
- struct list_head *next;
+ struct autofs_info *top_ino = autofs4_dentry_ino(top);
+ struct dentry *p;
- DPRINTK("parent %p %.*s",
+ DPRINTK("top %p %.*s",
top, (int)top->d_name.len, top->d_name.name);
/* Negative dentry - give up */
if (!simple_positive(top))
- return 0;
-
- /* Timeout of a tree mount is determined by its top dentry */
- if (!autofs4_can_expire(top, timeout, do_now))
- return 0;
-
- /* Is someone visiting anywhere in the tree ? */
- if (may_umount_tree(mnt))
- return 0;
+ return 1;
spin_lock(&dcache_lock);
-repeat:
- next = this_parent->d_subdirs.next;
-resume:
- while (next != &this_parent->d_subdirs) {
- struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
-
+ for (p = top; p; p = next_dentry(p, top)) {
/* Negative dentry - give up */
- if (!simple_positive(dentry)) {
- next = next->next;
+ if (!simple_positive(p))
continue;
- }
DPRINTK("dentry %p %.*s",
- dentry, (int)dentry->d_name.len, dentry->d_name.name);
-
- if (!simple_empty_nolock(dentry)) {
- this_parent = dentry;
- goto repeat;
- }
+ p, (int) p->d_name.len, p->d_name.name);
- dentry = dget(dentry);
+ p = dget(p);
spin_unlock(&dcache_lock);
- if (d_mountpoint(dentry)) {
- /* First busy => tree busy */
- if (!autofs4_check_mount(mnt, dentry)) {
- dput(dentry);
- return 0;
+ /*
+ * Is someone visiting anywhere in the subtree ?
+ * If there's no mount we need to check the usage
+ * count for the autofs dentry.
+ * If the fs is busy update the expiry counter.
+ */
+ if (d_mountpoint(p)) {
+ if (autofs4_mount_busy(mnt, p)) {
+ top_ino->last_used = jiffies;
+ dput(p);
+ return 1;
+ }
+ } else {
+ struct autofs_info *ino = autofs4_dentry_ino(p);
+ unsigned int ino_count = atomic_read(&ino->count);
+
+ /* allow for dget above and top is already dgot */
+ if (p == top)
+ ino_count += 2;
+ else
+ ino_count++;
+
+ if (atomic_read(&p->d_count) > ino_count) {
+ top_ino->last_used = jiffies;
+ dput(p);
+ return 1;
}
}
-
- dput(dentry);
+ dput(p);
spin_lock(&dcache_lock);
- next = next->next;
- }
-
- if (this_parent != top) {
- next = this_parent->d_u.d_child.next;
- this_parent = this_parent->d_parent;
- goto resume;
}
spin_unlock(&dcache_lock);
- return 1;
+ /* Timeout of a tree mount is ultimately determined by its top dentry */
+ if (!autofs4_can_expire(top, timeout, do_now))
+ return 1;
+
+ return 0;
}
static struct dentry *autofs4_check_leaves(struct vfsmount *mnt,
@@ -152,58 +203,68 @@ static struct dentry *autofs4_check_leaves(struct vfsmount *mnt,
unsigned long timeout,
int do_now)
{
- struct dentry *this_parent = parent;
- struct list_head *next;
+ struct dentry *p;
DPRINTK("parent %p %.*s",
parent, (int)parent->d_name.len, parent->d_name.name);
spin_lock(&dcache_lock);
-repeat:
- next = this_parent->d_subdirs.next;
-resume:
- while (next != &this_parent->d_subdirs) {
- struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
-
+ for (p = parent; p; p = next_dentry(p, parent)) {
/* Negative dentry - give up */
- if (!simple_positive(dentry)) {
- next = next->next;
+ if (!simple_positive(p))
continue;
- }
DPRINTK("dentry %p %.*s",
- dentry, (int)dentry->d_name.len, dentry->d_name.name);
-
- if (!list_empty(&dentry->d_subdirs)) {
- this_parent = dentry;
- goto repeat;
- }
+ p, (int) p->d_name.len, p->d_name.name);
- dentry = dget(dentry);
+ p = dget(p);
spin_unlock(&dcache_lock);
- if (d_mountpoint(dentry)) {
- /* Can we expire this guy */
- if (!autofs4_can_expire(dentry, timeout, do_now))
- goto cont;
-
+ if (d_mountpoint(p)) {
/* Can we umount this guy */
- if (autofs4_check_mount(mnt, dentry))
- return dentry;
+ if (autofs4_mount_busy(mnt, p))
+ goto cont;
+ /* Can we expire this guy */
+ if (autofs4_can_expire(p, timeout, do_now))
+ return p;
}
cont:
- dput(dentry);
+ dput(p);
spin_lock(&dcache_lock);
- next = next->next;
}
+ spin_unlock(&dcache_lock);
+ return NULL;
+}
+
+/* Check if we can expire a direct mount (possibly a tree) */
+static struct dentry *autofs4_expire_direct(struct super_block *sb,
+ struct vfsmount *mnt,
+ struct autofs_sb_info *sbi,
+ int how)
+{
+ unsigned long timeout;
+ struct dentry *root = dget(sb->s_root);
+ int do_now = how & AUTOFS_EXP_IMMEDIATE;
+
+ if (!sbi->exp_timeout || !root)
+ return NULL;
+
+ now = jiffies;
+ timeout = sbi->exp_timeout;
+
+ /* Lock the tree as we must expire as a whole */
+ spin_lock(&sbi->fs_lock);
+ if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
+ struct autofs_info *ino = autofs4_dentry_ino(root);
- if (this_parent != parent) {
- next = this_parent->d_u.d_child.next;
- this_parent = this_parent->d_parent;
- goto resume;
+ /* Set this flag early to catch sys_chdir and the like */
+ ino->flags |= AUTOFS_INF_EXPIRING;
+ spin_unlock(&sbi->fs_lock);
+ return root;
}
- spin_unlock(&dcache_lock);
+ spin_unlock(&sbi->fs_lock);
+ dput(root);
return NULL;
}
@@ -214,10 +275,10 @@ cont:
* - it is unused by any user process
* - it has been unused for exp_timeout time
*/
-static struct dentry *autofs4_expire(struct super_block *sb,
- struct vfsmount *mnt,
- struct autofs_sb_info *sbi,
- int how)
+static struct dentry *autofs4_expire_indirect(struct super_block *sb,
+ struct vfsmount *mnt,
+ struct autofs_sb_info *sbi,
+ int how)
{
unsigned long timeout;
struct dentry *root = sb->s_root;
@@ -241,7 +302,7 @@ static struct dentry *autofs4_expire(struct super_block *sb,
struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
/* Negative dentry - give up */
- if ( !simple_positive(dentry) ) {
+ if (!simple_positive(dentry)) {
next = next->next;
continue;
}
@@ -249,31 +310,36 @@ static struct dentry *autofs4_expire(struct super_block *sb,
dentry = dget(dentry);
spin_unlock(&dcache_lock);
- /* Case 1: indirect mount or top level direct mount */
+ /*
+ * Case 1: (i) indirect mount or top level pseudo direct mount
+ * (autofs-4.1).
+ * (ii) indirect mount with offset mount, check the "/"
+ * offset (autofs-5.0+).
+ */
if (d_mountpoint(dentry)) {
DPRINTK("checking mountpoint %p %.*s",
dentry, (int)dentry->d_name.len, dentry->d_name.name);
- /* Can we expire this guy */
- if (!autofs4_can_expire(dentry, timeout, do_now))
+ /* Can we umount this guy */
+ if (autofs4_mount_busy(mnt, dentry))
goto next;
- /* Can we umount this guy */
- if (autofs4_check_mount(mnt, dentry)) {
+ /* Can we expire this guy */
+ if (autofs4_can_expire(dentry, timeout, do_now)) {
expired = dentry;
break;
}
goto next;
}
- if ( simple_empty(dentry) )
+ if (simple_empty(dentry))
goto next;
/* Case 2: tree mount, expire iff entire tree is not busy */
if (!exp_leaves) {
/* Lock the tree as we must expire as a whole */
spin_lock(&sbi->fs_lock);
- if (autofs4_check_tree(mnt, dentry, timeout, do_now)) {
+ if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) {
struct autofs_info *inf = autofs4_dentry_ino(dentry);
/* Set this flag early to catch sys_chdir and the like */
@@ -283,7 +349,10 @@ static struct dentry *autofs4_expire(struct super_block *sb,
break;
}
spin_unlock(&sbi->fs_lock);
- /* Case 3: direct mount, expire individual leaves */
+ /*
+ * Case 3: pseudo direct mount, expire individual leaves
+ * (autofs-4.1).
+ */
} else {
expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
if (expired) {
@@ -297,7 +366,7 @@ next:
next = next->next;
}
- if ( expired ) {
+ if (expired) {
DPRINTK("returning %p %.*s",
expired, (int)expired->d_name.len, expired->d_name.name);
spin_lock(&dcache_lock);
@@ -325,7 +394,7 @@ int autofs4_expire_run(struct super_block *sb,
pkt.hdr.proto_version = sbi->version;
pkt.hdr.type = autofs_ptype_expire;
- if ((dentry = autofs4_expire(sb, mnt, sbi, 0)) == NULL)
+ if ((dentry = autofs4_expire_indirect(sb, mnt, sbi, 0)) == NULL)
return -EAGAIN;
pkt.len = dentry->d_name.len;
@@ -351,17 +420,22 @@ int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
if (arg && get_user(do_now, arg))
return -EFAULT;
- if ((dentry = autofs4_expire(sb, mnt, sbi, do_now)) != NULL) {
- struct autofs_info *de_info = autofs4_dentry_ino(dentry);
+ if (sbi->type & AUTOFS_TYPE_DIRECT)
+ dentry = autofs4_expire_direct(sb, mnt, sbi, do_now);
+ else
+ dentry = autofs4_expire_indirect(sb, mnt, sbi, do_now);
+
+ if (dentry) {
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
/* This is synchronous because it makes the daemon a
little easier */
- de_info->flags |= AUTOFS_INF_EXPIRING;
+ ino->flags |= AUTOFS_INF_EXPIRING;
ret = autofs4_wait(sbi, dentry, NFY_EXPIRE);
- de_info->flags &= ~AUTOFS_INF_EXPIRING;
+ ino->flags &= ~AUTOFS_INF_EXPIRING;
dput(dentry);
}
-
+
return ret;
}
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 1ad98d48e550..fde78b110ddd 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -3,6 +3,7 @@
* linux/fs/autofs/inode.c
*
* Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
+ * Copyright 2005-2006 Ian Kent <raven@themaw.net>
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
@@ -13,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/file.h>
+#include <linux/seq_file.h>
#include <linux/pagemap.h>
#include <linux/parser.h>
#include <linux/bitops.h>
@@ -46,6 +48,7 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
ino->size = 0;
ino->last_used = jiffies;
+ atomic_set(&ino->count, 0);
ino->sbi = sbi;
@@ -64,10 +67,19 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
void autofs4_free_ino(struct autofs_info *ino)
{
+ struct autofs_info *p_ino;
+
if (ino->dentry) {
ino->dentry->d_fsdata = NULL;
- if (ino->dentry->d_inode)
+ if (ino->dentry->d_inode) {
+ struct dentry *parent = ino->dentry->d_parent;
+ if (atomic_dec_and_test(&ino->count)) {
+ p_ino = autofs4_dentry_ino(parent);
+ if (p_ino && parent != ino->dentry)
+ atomic_dec(&p_ino->count);
+ }
dput(ino->dentry);
+ }
ino->dentry = NULL;
}
if (ino->free)
@@ -145,20 +157,44 @@ static void autofs4_put_super(struct super_block *sb)
autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */
/* Clean up and release dangling references */
- if (sbi)
- autofs4_force_release(sbi);
+ autofs4_force_release(sbi);
kfree(sbi);
DPRINTK("shutting down");
}
+static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+ struct autofs_sb_info *sbi = autofs4_sbi(mnt->mnt_sb);
+
+ if (!sbi)
+ return 0;
+
+ seq_printf(m, ",fd=%d", sbi->pipefd);
+ seq_printf(m, ",pgrp=%d", sbi->oz_pgrp);
+ seq_printf(m, ",timeout=%lu", sbi->exp_timeout/HZ);
+ seq_printf(m, ",minproto=%d", sbi->min_proto);
+ seq_printf(m, ",maxproto=%d", sbi->max_proto);
+
+ if (sbi->type & AUTOFS_TYPE_OFFSET)
+ seq_printf(m, ",offset");
+ else if (sbi->type & AUTOFS_TYPE_DIRECT)
+ seq_printf(m, ",direct");
+ else
+ seq_printf(m, ",indirect");
+
+ return 0;
+}
+
static struct super_operations autofs4_sops = {
.put_super = autofs4_put_super,
.statfs = simple_statfs,
+ .show_options = autofs4_show_options,
};
-enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto};
+enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto,
+ Opt_indirect, Opt_direct, Opt_offset};
static match_table_t tokens = {
{Opt_fd, "fd=%u"},
@@ -167,11 +203,15 @@ static match_table_t tokens = {
{Opt_pgrp, "pgrp=%u"},
{Opt_minproto, "minproto=%u"},
{Opt_maxproto, "maxproto=%u"},
+ {Opt_indirect, "indirect"},
+ {Opt_direct, "direct"},
+ {Opt_offset, "offset"},
{Opt_err, NULL}
};
static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
- pid_t *pgrp, int *minproto, int *maxproto)
+ pid_t *pgrp, unsigned int *type,
+ int *minproto, int *maxproto)
{
char *p;
substring_t args[MAX_OPT_ARGS];
@@ -225,6 +265,15 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
return 1;
*maxproto = option;
break;
+ case Opt_indirect:
+ *type = AUTOFS_TYPE_INDIRECT;
+ break;
+ case Opt_direct:
+ *type = AUTOFS_TYPE_DIRECT;
+ break;
+ case Opt_offset:
+ *type = AUTOFS_TYPE_DIRECT | AUTOFS_TYPE_OFFSET;
+ break;
default:
return 1;
}
@@ -243,6 +292,10 @@ static struct autofs_info *autofs4_mkroot(struct autofs_sb_info *sbi)
return ino;
}
+static struct dentry_operations autofs4_sb_dentry_operations = {
+ .d_release = autofs4_dentry_release,
+};
+
int autofs4_fill_super(struct super_block *s, void *data, int silent)
{
struct inode * root_inode;
@@ -251,7 +304,6 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
int pipefd;
struct autofs_sb_info *sbi;
struct autofs_info *ino;
- int minproto, maxproto;
sbi = (struct autofs_sb_info *) kmalloc(sizeof(*sbi), GFP_KERNEL);
if ( !sbi )
@@ -263,12 +315,16 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
s->s_fs_info = sbi;
sbi->magic = AUTOFS_SBI_MAGIC;
sbi->root = NULL;
+ sbi->pipefd = -1;
sbi->catatonic = 0;
sbi->exp_timeout = 0;
sbi->oz_pgrp = process_group(current);
sbi->sb = s;
sbi->version = 0;
sbi->sub_version = 0;
+ sbi->type = 0;
+ sbi->min_proto = 0;
+ sbi->max_proto = 0;
mutex_init(&sbi->wq_mutex);
spin_lock_init(&sbi->fs_lock);
sbi->queues = NULL;
@@ -285,38 +341,46 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
if (!ino)
goto fail_free;
root_inode = autofs4_get_inode(s, ino);
- kfree(ino);
if (!root_inode)
- goto fail_free;
+ goto fail_ino;
- root_inode->i_op = &autofs4_root_inode_operations;
- root_inode->i_fop = &autofs4_root_operations;
root = d_alloc_root(root_inode);
- pipe = NULL;
-
if (!root)
goto fail_iput;
+ pipe = NULL;
+
+ root->d_op = &autofs4_sb_dentry_operations;
+ root->d_fsdata = ino;
/* Can this call block? */
if (parse_options(data, &pipefd,
&root_inode->i_uid, &root_inode->i_gid,
- &sbi->oz_pgrp,
- &minproto, &maxproto)) {
+ &sbi->oz_pgrp, &sbi->type,
+ &sbi->min_proto, &sbi->max_proto)) {
printk("autofs: called with bogus options\n");
goto fail_dput;
}
+ root_inode->i_fop = &autofs4_root_operations;
+ root_inode->i_op = sbi->type & AUTOFS_TYPE_DIRECT ?
+ &autofs4_direct_root_inode_operations :
+ &autofs4_indirect_root_inode_operations;
+
/* Couldn't this be tested earlier? */
- if (maxproto < AUTOFS_MIN_PROTO_VERSION ||
- minproto > AUTOFS_MAX_PROTO_VERSION) {
+ if (sbi->max_proto < AUTOFS_MIN_PROTO_VERSION ||
+ sbi->min_proto > AUTOFS_MAX_PROTO_VERSION) {
printk("autofs: kernel does not match daemon version "
"daemon (%d, %d) kernel (%d, %d)\n",
- minproto, maxproto,
+ sbi->min_proto, sbi->max_proto,
AUTOFS_MIN_PROTO_VERSION, AUTOFS_MAX_PROTO_VERSION);
goto fail_dput;
}
- sbi->version = maxproto > AUTOFS_MAX_PROTO_VERSION ? AUTOFS_MAX_PROTO_VERSION : maxproto;
+ /* Establish highest kernel protocol version */
+ if (sbi->max_proto > AUTOFS_MAX_PROTO_VERSION)
+ sbi->version = AUTOFS_MAX_PROTO_VERSION;
+ else
+ sbi->version = sbi->max_proto;
sbi->sub_version = AUTOFS_PROTO_SUBVERSION;
DPRINTK("pipe fd = %d, pgrp = %u", pipefd, sbi->oz_pgrp);
@@ -329,6 +393,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
if ( !pipe->f_op || !pipe->f_op->write )
goto fail_fput;
sbi->pipe = pipe;
+ sbi->pipefd = pipefd;
/*
* Take a reference to the root dentry so we get a chance to
@@ -356,6 +421,8 @@ fail_dput:
fail_iput:
printk("autofs: get root dentry failed\n");
iput(root_inode);
+fail_ino:
+ kfree(ino);
fail_free:
kfree(sbi);
fail_unlock:
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 62d8d4acb8bb..84e030c8ddd0 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -4,7 +4,7 @@
*
* Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
* Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org>
- * Copyright 2001-2003 Ian Kent <raven@themaw.net>
+ * Copyright 2001-2006 Ian Kent <raven@themaw.net>
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
@@ -30,9 +30,9 @@ static int autofs4_dir_close(struct inode *inode, struct file *file);
static int autofs4_dir_readdir(struct file * filp, void * dirent, filldir_t filldir);
static int autofs4_root_readdir(struct file * filp, void * dirent, filldir_t filldir);
static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
-static int autofs4_dcache_readdir(struct file *, void *, filldir_t);
+static void *autofs4_follow_link(struct dentry *, struct nameidata *);
-struct file_operations autofs4_root_operations = {
+const struct file_operations autofs4_root_operations = {
.open = dcache_dir_open,
.release = dcache_dir_close,
.read = generic_read_dir,
@@ -40,14 +40,14 @@ struct file_operations autofs4_root_operations = {
.ioctl = autofs4_root_ioctl,
};
-struct file_operations autofs4_dir_operations = {
+const struct file_operations autofs4_dir_operations = {
.open = autofs4_dir_open,
.release = autofs4_dir_close,
.read = generic_read_dir,
.readdir = autofs4_dir_readdir,
};
-struct inode_operations autofs4_root_inode_operations = {
+struct inode_operations autofs4_indirect_root_inode_operations = {
.lookup = autofs4_lookup,
.unlink = autofs4_dir_unlink,
.symlink = autofs4_dir_symlink,
@@ -55,6 +55,14 @@ struct inode_operations autofs4_root_inode_operations = {
.rmdir = autofs4_dir_rmdir,
};
+struct inode_operations autofs4_direct_root_inode_operations = {
+ .lookup = autofs4_lookup,
+ .unlink = autofs4_dir_unlink,
+ .mkdir = autofs4_dir_mkdir,
+ .rmdir = autofs4_dir_rmdir,
+ .follow_link = autofs4_follow_link,
+};
+
struct inode_operations autofs4_dir_inode_operations = {
.lookup = autofs4_lookup,
.unlink = autofs4_dir_unlink,
@@ -82,87 +90,7 @@ static int autofs4_root_readdir(struct file *file, void *dirent,
DPRINTK("needs_reghost = %d", sbi->needs_reghost);
- return autofs4_dcache_readdir(file, dirent, filldir);
-}
-
-/* Update usage from here to top of tree, so that scan of
- top-level directories will give a useful result */
-static void autofs4_update_usage(struct vfsmount *mnt, struct dentry *dentry)
-{
- struct dentry *top = dentry->d_sb->s_root;
-
- spin_lock(&dcache_lock);
- for(; dentry != top; dentry = dentry->d_parent) {
- struct autofs_info *ino = autofs4_dentry_ino(dentry);
-
- if (ino) {
- touch_atime(mnt, dentry);
- ino->last_used = jiffies;
- }
- }
- spin_unlock(&dcache_lock);
-}
-
-/*
- * From 2.4 kernel readdir.c
- */
-static int autofs4_dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
-{
- int i;
- struct dentry *dentry = filp->f_dentry;
-
- i = filp->f_pos;
- switch (i) {
- case 0:
- if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino, DT_DIR) < 0)
- break;
- i++;
- filp->f_pos++;
- /* fallthrough */
- case 1:
- if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
- break;
- i++;
- filp->f_pos++;
- /* fallthrough */
- default: {
- struct list_head *list;
- int j = i-2;
-
- spin_lock(&dcache_lock);
- list = dentry->d_subdirs.next;
-
- for (;;) {
- if (list == &dentry->d_subdirs) {
- spin_unlock(&dcache_lock);
- return 0;
- }
- if (!j)
- break;
- j--;
- list = list->next;
- }
-
- while(1) {
- struct dentry *de = list_entry(list,
- struct dentry, d_u.d_child);
-
- if (!d_unhashed(de) && de->d_inode) {
- spin_unlock(&dcache_lock);
- if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino, DT_UNKNOWN) < 0)
- break;
- spin_lock(&dcache_lock);
- }
- filp->f_pos++;
- list = list->next;
- if (list != &dentry->d_subdirs)
- continue;
- spin_unlock(&dcache_lock);
- break;
- }
- }
- }
- return 0;
+ return dcache_readdir(file, dirent, filldir);
}
static int autofs4_dir_open(struct inode *inode, struct file *file)
@@ -170,8 +98,16 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
struct dentry *dentry = file->f_dentry;
struct vfsmount *mnt = file->f_vfsmnt;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+ struct dentry *cursor;
int status;
+ status = dcache_dir_open(inode, file);
+ if (status)
+ goto out;
+
+ cursor = file->private_data;
+ cursor->d_fsdata = NULL;
+
DPRINTK("file=%p dentry=%p %.*s",
file, dentry, dentry->d_name.len, dentry->d_name.name);
@@ -180,12 +116,15 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
if (autofs4_ispending(dentry)) {
DPRINTK("dentry busy");
- return -EBUSY;
+ dcache_dir_close(inode, file);
+ status = -EBUSY;
+ goto out;
}
+ status = -ENOENT;
if (!d_mountpoint(dentry) && dentry->d_op && dentry->d_op->d_revalidate) {
struct nameidata nd;
- int empty;
+ int empty, ret;
/* In case there are stale directory dentrys from a failed mount */
spin_lock(&dcache_lock);
@@ -195,13 +134,13 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
if (!empty)
d_invalidate(dentry);
- nd.dentry = dentry;
- nd.mnt = mnt;
nd.flags = LOOKUP_DIRECTORY;
- status = (dentry->d_op->d_revalidate)(dentry, &nd);
+ ret = (dentry->d_op->d_revalidate)(dentry, &nd);
- if (!status)
- return -ENOENT;
+ if (!ret) {
+ dcache_dir_close(inode, file);
+ goto out;
+ }
}
if (d_mountpoint(dentry)) {
@@ -212,25 +151,29 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) {
dput(fp_dentry);
mntput(fp_mnt);
- return -ENOENT;
+ dcache_dir_close(inode, file);
+ goto out;
}
fp = dentry_open(fp_dentry, fp_mnt, file->f_flags);
status = PTR_ERR(fp);
if (IS_ERR(fp)) {
- file->private_data = NULL;
- return status;
+ dcache_dir_close(inode, file);
+ goto out;
}
- file->private_data = fp;
+ cursor->d_fsdata = fp;
}
-out:
return 0;
+out:
+ return status;
}
static int autofs4_dir_close(struct inode *inode, struct file *file)
{
struct dentry *dentry = file->f_dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+ struct dentry *cursor = file->private_data;
+ int status = 0;
DPRINTK("file=%p dentry=%p %.*s",
file, dentry, dentry->d_name.len, dentry->d_name.name);
@@ -240,26 +183,28 @@ static int autofs4_dir_close(struct inode *inode, struct file *file)
if (autofs4_ispending(dentry)) {
DPRINTK("dentry busy");
- return -EBUSY;
+ status = -EBUSY;
+ goto out;
}
if (d_mountpoint(dentry)) {
- struct file *fp = file->private_data;
-
- if (!fp)
- return -ENOENT;
-
+ struct file *fp = cursor->d_fsdata;
+ if (!fp) {
+ status = -ENOENT;
+ goto out;
+ }
filp_close(fp, current->files);
- file->private_data = NULL;
}
out:
- return 0;
+ dcache_dir_close(inode, file);
+ return status;
}
static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldir)
{
struct dentry *dentry = file->f_dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+ struct dentry *cursor = file->private_data;
int status;
DPRINTK("file=%p dentry=%p %.*s",
@@ -274,7 +219,7 @@ static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldi
}
if (d_mountpoint(dentry)) {
- struct file *fp = file->private_data;
+ struct file *fp = cursor->d_fsdata;
if (!fp)
return -ENOENT;
@@ -289,27 +234,26 @@ static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldi
return status;
}
out:
- return autofs4_dcache_readdir(file, dirent, filldir);
+ return dcache_readdir(file, dirent, filldir);
}
-static int try_to_fill_dentry(struct vfsmount *mnt, struct dentry *dentry, int flags)
+static int try_to_fill_dentry(struct dentry *dentry, int flags)
{
- struct super_block *sb = mnt->mnt_sb;
- struct autofs_sb_info *sbi = autofs4_sbi(sb);
- struct autofs_info *de_info = autofs4_dentry_ino(dentry);
+ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
int status = 0;
/* Block on any pending expiry here; invalidate the dentry
when expiration is done to trigger mount request with a new
dentry */
- if (de_info && (de_info->flags & AUTOFS_INF_EXPIRING)) {
+ if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) {
DPRINTK("waiting for expire %p name=%.*s",
dentry, dentry->d_name.len, dentry->d_name.name);
status = autofs4_wait(sbi, dentry, NFY_NONE);
-
+
DPRINTK("expire done status=%d", status);
-
+
/*
* If the directory still exists the mount request must
* continue otherwise it can't be followed at the right
@@ -317,34 +261,36 @@ static int try_to_fill_dentry(struct vfsmount *mnt, struct dentry *dentry, int f
*/
status = d_invalidate(dentry);
if (status != -EBUSY)
- return 0;
+ return -ENOENT;
}
DPRINTK("dentry=%p %.*s ino=%p",
dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
- /* Wait for a pending mount, triggering one if there isn't one already */
+ /*
+ * Wait for a pending mount, triggering one if there
+ * isn't one already
+ */
if (dentry->d_inode == NULL) {
DPRINTK("waiting for mount name=%.*s",
dentry->d_name.len, dentry->d_name.name);
status = autofs4_wait(sbi, dentry, NFY_MOUNT);
-
+
DPRINTK("mount done status=%d", status);
if (status && dentry->d_inode)
- return 0; /* Try to get the kernel to invalidate this dentry */
-
+ return status; /* Try to get the kernel to invalidate this dentry */
+
/* Turn this into a real negative dentry? */
if (status == -ENOENT) {
- dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT;
spin_lock(&dentry->d_lock);
dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
spin_unlock(&dentry->d_lock);
- return 1;
+ return status;
} else if (status) {
/* Return a negative dentry, but leave it "pending" */
- return 1;
+ return status;
}
/* Trigger mount for path component or follow link */
} else if (flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) ||
@@ -363,19 +309,87 @@ static int try_to_fill_dentry(struct vfsmount *mnt, struct dentry *dentry, int f
spin_lock(&dentry->d_lock);
dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
spin_unlock(&dentry->d_lock);
- return 0;
+ return status;
}
}
- /* We don't update the usages for the autofs daemon itself, this
- is necessary for recursive autofs mounts */
- if (!autofs4_oz_mode(sbi))
- autofs4_update_usage(mnt, dentry);
+ /* Initialize expiry counter after successful mount */
+ if (ino)
+ ino->last_used = jiffies;
spin_lock(&dentry->d_lock);
dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
spin_unlock(&dentry->d_lock);
- return 1;
+ return status;
+}
+
+/* For autofs direct mounts the follow link triggers the mount */
+static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+ int oz_mode = autofs4_oz_mode(sbi);
+ unsigned int lookup_type;
+ int status;
+
+ DPRINTK("dentry=%p %.*s oz_mode=%d nd->flags=%d",
+ dentry, dentry->d_name.len, dentry->d_name.name, oz_mode,
+ nd->flags);
+
+ /* If it's our master or we shouldn't trigger a mount we're done */
+ lookup_type = nd->flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY);
+ if (oz_mode || !lookup_type)
+ goto done;
+
+ /*
+ * If a request is pending wait for it.
+ * If it's a mount then it won't be expired till at least
+ * a liitle later and if it's an expire then we might need
+ * to mount it again.
+ */
+ if (autofs4_ispending(dentry)) {
+ DPRINTK("waiting for active request %p name=%.*s",
+ dentry, dentry->d_name.len, dentry->d_name.name);
+
+ status = autofs4_wait(sbi, dentry, NFY_NONE);
+
+ DPRINTK("request done status=%d", status);
+ }
+
+ /*
+ * If the dentry contains directories then it is an
+ * autofs multi-mount with no root mount offset. So
+ * don't try to mount it again.
+ */
+ spin_lock(&dcache_lock);
+ if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
+ spin_unlock(&dcache_lock);
+
+ status = try_to_fill_dentry(dentry, 0);
+ if (status)
+ goto out_error;
+
+ /*
+ * The mount succeeded but if there is no root mount
+ * it must be an autofs multi-mount with no root offset
+ * so we don't need to follow the mount.
+ */
+ if (d_mountpoint(dentry)) {
+ if (!autofs4_follow_mount(&nd->mnt, &nd->dentry)) {
+ status = -ENOENT;
+ goto out_error;
+ }
+ }
+
+ goto done;
+ }
+ spin_unlock(&dcache_lock);
+
+done:
+ return NULL;
+
+out_error:
+ path_release(nd);
+ return ERR_PTR(status);
}
/*
@@ -384,47 +398,43 @@ static int try_to_fill_dentry(struct vfsmount *mnt, struct dentry *dentry, int f
* yet completely filled in, and revalidate has to delay such
* lookups..
*/
-static int autofs4_revalidate(struct dentry * dentry, struct nameidata *nd)
+static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
{
- struct inode * dir = dentry->d_parent->d_inode;
+ struct inode *dir = dentry->d_parent->d_inode;
struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
int oz_mode = autofs4_oz_mode(sbi);
int flags = nd ? nd->flags : 0;
- int status = 1;
+ int status = 0;
/* Pending dentry */
if (autofs4_ispending(dentry)) {
if (!oz_mode)
- status = try_to_fill_dentry(nd->mnt, dentry, flags);
- return status;
+ status = try_to_fill_dentry(dentry, flags);
+ return !status;
}
/* Negative dentry.. invalidate if "old" */
if (dentry->d_inode == NULL)
- return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT);
+ return 0;
/* Check for a non-mountpoint directory with no contents */
spin_lock(&dcache_lock);
if (S_ISDIR(dentry->d_inode->i_mode) &&
!d_mountpoint(dentry) &&
- list_empty(&dentry->d_subdirs)) {
+ __simple_empty(dentry)) {
DPRINTK("dentry=%p %.*s, emptydir",
dentry, dentry->d_name.len, dentry->d_name.name);
spin_unlock(&dcache_lock);
if (!oz_mode)
- status = try_to_fill_dentry(nd->mnt, dentry, flags);
- return status;
+ status = try_to_fill_dentry(dentry, flags);
+ return !status;
}
spin_unlock(&dcache_lock);
- /* Update the usage list */
- if (!oz_mode)
- autofs4_update_usage(nd->mnt, dentry);
-
return 1;
}
-static void autofs4_dentry_release(struct dentry *de)
+void autofs4_dentry_release(struct dentry *de)
{
struct autofs_info *inf;
@@ -462,12 +472,13 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
DPRINTK("name = %.*s",
dentry->d_name.len, dentry->d_name.name);
+ /* File name too long to exist */
if (dentry->d_name.len > NAME_MAX)
- return ERR_PTR(-ENAMETOOLONG);/* File name too long to exist */
+ return ERR_PTR(-ENAMETOOLONG);
sbi = autofs4_sbi(dir->i_sb);
-
oz_mode = autofs4_oz_mode(sbi);
+
DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d",
current->pid, process_group(current), sbi->catatonic, oz_mode);
@@ -519,7 +530,7 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
* doesn't do the right thing for all system calls, but it should
* be OK for the operations we permit from an autofs.
*/
- if ( dentry->d_inode && d_unhashed(dentry) )
+ if (dentry->d_inode && d_unhashed(dentry))
return ERR_PTR(-ENOENT);
return NULL;
@@ -531,6 +542,7 @@ static int autofs4_dir_symlink(struct inode *dir,
{
struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
+ struct autofs_info *p_ino;
struct inode *inode;
char *cp;
@@ -564,6 +576,10 @@ static int autofs4_dir_symlink(struct inode *dir,
dentry->d_fsdata = ino;
ino->dentry = dget(dentry);
+ atomic_inc(&ino->count);
+ p_ino = autofs4_dentry_ino(dentry->d_parent);
+ if (p_ino && dentry->d_parent != dentry)
+ atomic_inc(&p_ino->count);
ino->inode = inode;
dir->i_mtime = CURRENT_TIME;
@@ -590,11 +606,17 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
{
struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
+ struct autofs_info *p_ino;
/* This allows root to remove symlinks */
if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
return -EACCES;
+ if (atomic_dec_and_test(&ino->count)) {
+ p_ino = autofs4_dentry_ino(dentry->d_parent);
+ if (p_ino && dentry->d_parent != dentry)
+ atomic_dec(&p_ino->count);
+ }
dput(ino->dentry);
dentry->d_inode->i_size = 0;
@@ -611,6 +633,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
{
struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
+ struct autofs_info *p_ino;
if (!autofs4_oz_mode(sbi))
return -EACCES;
@@ -625,8 +648,12 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
+ if (atomic_dec_and_test(&ino->count)) {
+ p_ino = autofs4_dentry_ino(dentry->d_parent);
+ if (p_ino && dentry->d_parent != dentry)
+ atomic_dec(&p_ino->count);
+ }
dput(ino->dentry);
-
dentry->d_inode->i_size = 0;
dentry->d_inode->i_nlink = 0;
@@ -640,6 +667,7 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
+ struct autofs_info *p_ino;
struct inode *inode;
if ( !autofs4_oz_mode(sbi) )
@@ -662,6 +690,10 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
dentry->d_fsdata = ino;
ino->dentry = dget(dentry);
+ atomic_inc(&ino->count);
+ p_ino = autofs4_dentry_ino(dentry->d_parent);
+ if (p_ino && dentry->d_parent != dentry)
+ atomic_inc(&p_ino->count);
ino->inode = inode;
dir->i_nlink++;
dir->i_mtime = CURRENT_TIME;
@@ -745,7 +777,7 @@ static inline int autofs4_ask_umount(struct vfsmount *mnt, int __user *p)
{
int status = 0;
- if (may_umount(mnt) == 0)
+ if (may_umount(mnt))
status = 1;
DPRINTK("returning %d", status);
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index be78e9378c03..142ab6aa2aa1 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -3,7 +3,7 @@
* linux/fs/autofs/waitq.c
*
* Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
- * Copyright 2001-2003 Ian Kent <raven@themaw.net>
+ * Copyright 2001-2006 Ian Kent <raven@themaw.net>
*
* This file is part of the Linux kernel and is made available under
* the terms of the GNU General Public License, version 2, or at your
@@ -33,7 +33,7 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi)
sbi->catatonic = 1;
wq = sbi->queues;
sbi->queues = NULL; /* Erase all wait queues */
- while ( wq ) {
+ while (wq) {
nwq = wq->next;
wq->status = -ENOENT; /* Magic is gone - report failure */
kfree(wq->name);
@@ -45,7 +45,6 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi)
fput(sbi->pipe); /* Close the pipe */
sbi->pipe = NULL;
}
-
shrink_dcache_sb(sbi->sb);
}
@@ -98,7 +97,10 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
pkt.hdr.proto_version = sbi->version;
pkt.hdr.type = type;
- if (type == autofs_ptype_missing) {
+ switch (type) {
+ /* Kernel protocol v4 missing and expire packets */
+ case autofs_ptype_missing:
+ {
struct autofs_packet_missing *mp = &pkt.missing;
pktsz = sizeof(*mp);
@@ -107,7 +109,10 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
mp->len = wq->len;
memcpy(mp->name, wq->name, wq->len);
mp->name[wq->len] = '\0';
- } else if (type == autofs_ptype_expire_multi) {
+ break;
+ }
+ case autofs_ptype_expire_multi:
+ {
struct autofs_packet_expire_multi *ep = &pkt.expire_multi;
pktsz = sizeof(*ep);
@@ -116,7 +121,34 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
ep->len = wq->len;
memcpy(ep->name, wq->name, wq->len);
ep->name[wq->len] = '\0';
- } else {
+ break;
+ }
+ /*
+ * Kernel protocol v5 packet for handling indirect and direct
+ * mount missing and expire requests
+ */
+ case autofs_ptype_missing_indirect:
+ case autofs_ptype_expire_indirect:
+ case autofs_ptype_missing_direct:
+ case autofs_ptype_expire_direct:
+ {
+ struct autofs_v5_packet *packet = &pkt.v5_packet;
+
+ pktsz = sizeof(*packet);
+
+ packet->wait_queue_token = wq->wait_queue_token;
+ packet->len = wq->len;
+ memcpy(packet->name, wq->name, wq->len);
+ packet->name[wq->len] = '\0';
+ packet->dev = wq->dev;
+ packet->ino = wq->ino;
+ packet->uid = wq->uid;
+ packet->gid = wq->gid;
+ packet->pid = wq->pid;
+ packet->tgid = wq->tgid;
+ break;
+ }
+ default:
printk("autofs4_notify_daemon: bad type %d!\n", type);
return;
}
@@ -162,21 +194,29 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
{
struct autofs_wait_queue *wq;
char *name;
- int len, status;
+ unsigned int len = 0;
+ unsigned int hash = 0;
+ int status;
/* In catatonic mode, we don't wait for nobody */
- if ( sbi->catatonic )
+ if (sbi->catatonic)
return -ENOENT;
name = kmalloc(NAME_MAX + 1, GFP_KERNEL);
if (!name)
return -ENOMEM;
- len = autofs4_getpath(sbi, dentry, &name);
- if (!len) {
- kfree(name);
- return -ENOENT;
+ /* If this is a direct mount request create a dummy name */
+ if (IS_ROOT(dentry) && (sbi->type & AUTOFS_TYPE_DIRECT))
+ len = sprintf(name, "%p", dentry);
+ else {
+ len = autofs4_getpath(sbi, dentry, &name);
+ if (!len) {
+ kfree(name);
+ return -ENOENT;
+ }
}
+ hash = full_name_hash(name, len);
if (mutex_lock_interruptible(&sbi->wq_mutex)) {
kfree(name);
@@ -190,7 +230,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
break;
}
- if ( !wq ) {
+ if (!wq) {
/* Can't wait for an expire if there's no mount */
if (notify == NFY_NONE && !d_mountpoint(dentry)) {
kfree(name);
@@ -200,7 +240,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
/* Create a new wait queue */
wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL);
- if ( !wq ) {
+ if (!wq) {
kfree(name);
mutex_unlock(&sbi->wq_mutex);
return -ENOMEM;
@@ -212,12 +252,18 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
wq->next = sbi->queues;
sbi->queues = wq;
init_waitqueue_head(&wq->queue);
- wq->hash = dentry->d_name.hash;
+ wq->hash = hash;
wq->name = name;
wq->len = len;
+ wq->dev = autofs4_get_dev(sbi);
+ wq->ino = autofs4_get_ino(sbi);
+ wq->uid = current->uid;
+ wq->gid = current->gid;
+ wq->pid = current->pid;
+ wq->tgid = current->tgid;
wq->status = -EINTR; /* Status return if interrupted */
atomic_set(&wq->wait_ctr, 2);
- atomic_set(&wq->notified, 1);
+ atomic_set(&wq->notify, 1);
mutex_unlock(&sbi->wq_mutex);
} else {
atomic_inc(&wq->wait_ctr);
@@ -227,9 +273,26 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
(unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
}
- if (notify != NFY_NONE && atomic_dec_and_test(&wq->notified)) {
- int type = (notify == NFY_MOUNT ?
- autofs_ptype_missing : autofs_ptype_expire_multi);
+ if (notify != NFY_NONE && atomic_read(&wq->notify)) {
+ int type;
+
+ atomic_dec(&wq->notify);
+
+ if (sbi->version < 5) {
+ if (notify == NFY_MOUNT)
+ type = autofs_ptype_missing;
+ else
+ type = autofs_ptype_expire_multi;
+ } else {
+ if (notify == NFY_MOUNT)
+ type = (sbi->type & AUTOFS_TYPE_DIRECT) ?
+ autofs_ptype_missing_direct :
+ autofs_ptype_missing_indirect;
+ else
+ type = (sbi->type & AUTOFS_TYPE_DIRECT) ?
+ autofs_ptype_expire_direct :
+ autofs_ptype_expire_indirect;
+ }
DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n",
(unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
@@ -240,14 +303,14 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
/* wq->name is NULL if and only if the lock is already released */
- if ( sbi->catatonic ) {
+ if (sbi->catatonic) {
/* We might have slept, so check again for catatonic mode */
wq->status = -ENOENT;
kfree(wq->name);
wq->name = NULL;
}
- if ( wq->name ) {
+ if (wq->name) {
/* Block all but "shutdown" signals while waiting */
sigset_t oldset;
unsigned long irqflags;
@@ -283,12 +346,12 @@ int autofs4_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_tok
struct autofs_wait_queue *wq, **wql;
mutex_lock(&sbi->wq_mutex);
- for ( wql = &sbi->queues ; (wq = *wql) != 0 ; wql = &wq->next ) {
- if ( wq->wait_queue_token == wait_queue_token )
+ for (wql = &sbi->queues ; (wq = *wql) != 0 ; wql = &wq->next) {
+ if (wq->wait_queue_token == wait_queue_token)
break;
}
- if ( !wq ) {
+ if (!wq) {
mutex_unlock(&sbi->wq_mutex);
return -EINVAL;
}
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index e172180a1d8c..80599ae33966 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -22,7 +22,7 @@ static int return_EIO(void)
#define EIO_ERROR ((void *) (return_EIO))
-static struct file_operations bad_file_ops =
+static const struct file_operations bad_file_ops =
{
.llseek = EIO_ERROR,
.aio_read = EIO_ERROR,
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 044a59587829..68ebd10f345d 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -64,7 +64,7 @@ static const struct super_operations befs_sops = {
/* slab cache for befs_inode_info objects */
static kmem_cache_t *befs_inode_cachep;
-static struct file_operations befs_dir_operations = {
+static const struct file_operations befs_dir_operations = {
.read = generic_read_dir,
.readdir = befs_readdir,
};
diff --git a/fs/bfs/bfs.h b/fs/bfs/bfs.h
index 1fbc53f14aba..9d791004b21c 100644
--- a/fs/bfs/bfs.h
+++ b/fs/bfs/bfs.h
@@ -49,11 +49,11 @@ static inline struct bfs_inode_info *BFS_I(struct inode *inode)
/* file.c */
extern struct inode_operations bfs_file_inops;
-extern struct file_operations bfs_file_operations;
+extern const struct file_operations bfs_file_operations;
extern struct address_space_operations bfs_aops;
/* dir.c */
extern struct inode_operations bfs_dir_inops;
-extern struct file_operations bfs_dir_operations;
+extern const struct file_operations bfs_dir_operations;
#endif /* _FS_BFS_BFS_H */
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 5af928fa0449..26fad9621738 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -70,7 +70,7 @@ static int bfs_readdir(struct file * f, void * dirent, filldir_t filldir)
return 0;
}
-struct file_operations bfs_dir_operations = {
+const struct file_operations bfs_dir_operations = {
.read = generic_read_dir,
.readdir = bfs_readdir,
.fsync = file_fsync,
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
index 807723b65daf..d83cd74a2e4e 100644
--- a/fs/bfs/file.c
+++ b/fs/bfs/file.c
@@ -17,7 +17,7 @@
#define dprintf(x...)
#endif
-struct file_operations bfs_file_operations = {
+const struct file_operations bfs_file_operations = {
.llseek = generic_file_llseek,
.read = generic_file_read,
.write = generic_file_write,
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 6a7b730c206b..d73d75591a39 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -600,7 +600,7 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
return count;
}
-static struct file_operations bm_entry_operations = {
+static const struct file_operations bm_entry_operations = {
.read = bm_entry_read,
.write = bm_entry_write,
};
@@ -668,7 +668,7 @@ out:
return count;
}
-static struct file_operations bm_register_operations = {
+static const struct file_operations bm_register_operations = {
.write = bm_register_write,
};
@@ -715,7 +715,7 @@ static ssize_t bm_status_write(struct file * file, const char __user * buffer,
return count;
}
-static struct file_operations bm_status_operations = {
+static const struct file_operations bm_status_operations = {
.read = bm_status_read,
.write = bm_status_write,
};
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 5983d42df015..af88c43043d5 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -266,6 +266,9 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
mutex_init(&bdev->bd_mount_mutex);
INIT_LIST_HEAD(&bdev->bd_inodes);
INIT_LIST_HEAD(&bdev->bd_list);
+#ifdef CONFIG_SYSFS
+ INIT_LIST_HEAD(&bdev->bd_holder_list);
+#endif
inode_init_once(&ei->vfs_inode);
}
}
@@ -490,6 +493,300 @@ void bd_release(struct block_device *bdev)
EXPORT_SYMBOL(bd_release);
+#ifdef CONFIG_SYSFS
+/*
+ * Functions for bd_claim_by_kobject / bd_release_from_kobject
+ *
+ * If a kobject is passed to bd_claim_by_kobject()
+ * and the kobject has a parent directory,
+ * following symlinks are created:
+ * o from the kobject to the claimed bdev
+ * o from "holders" directory of the bdev to the parent of the kobject
+ * bd_release_from_kobject() removes these symlinks.
+ *
+ * Example:
+ * If /dev/dm-0 maps to /dev/sda, kobject corresponding to
+ * /sys/block/dm-0/slaves is passed to bd_claim_by_kobject(), then:
+ * /sys/block/dm-0/slaves/sda --> /sys/block/sda
+ * /sys/block/sda/holders/dm-0 --> /sys/block/dm-0
+ */
+
+static struct kobject *bdev_get_kobj(struct block_device *bdev)
+{
+ if (bdev->bd_contains != bdev)
+ return kobject_get(&bdev->bd_part->kobj);
+ else
+ return kobject_get(&bdev->bd_disk->kobj);
+}
+
+static struct kobject *bdev_get_holder(struct block_device *bdev)
+{
+ if (bdev->bd_contains != bdev)
+ return kobject_get(bdev->bd_part->holder_dir);
+ else
+ return kobject_get(bdev->bd_disk->holder_dir);
+}
+
+static void add_symlink(struct kobject *from, struct kobject *to)
+{
+ if (!from || !to)
+ return;
+ sysfs_create_link(from, to, kobject_name(to));
+}
+
+static void del_symlink(struct kobject *from, struct kobject *to)
+{
+ if (!from || !to)
+ return;
+ sysfs_remove_link(from, kobject_name(to));
+}
+
+/*
+ * 'struct bd_holder' contains pointers to kobjects symlinked by
+ * bd_claim_by_kobject.
+ * It's connected to bd_holder_list which is protected by bdev->bd_sem.
+ */
+struct bd_holder {
+ struct list_head list; /* chain of holders of the bdev */
+ int count; /* references from the holder */
+ struct kobject *sdir; /* holder object, e.g. "/block/dm-0/slaves" */
+ struct kobject *hdev; /* e.g. "/block/dm-0" */
+ struct kobject *hdir; /* e.g. "/block/sda/holders" */
+ struct kobject *sdev; /* e.g. "/block/sda" */
+};
+
+/*
+ * Get references of related kobjects at once.
+ * Returns 1 on success. 0 on failure.
+ *
+ * Should call bd_holder_release_dirs() after successful use.
+ */
+static int bd_holder_grab_dirs(struct block_device *bdev,
+ struct bd_holder *bo)
+{
+ if (!bdev || !bo)
+ return 0;
+
+ bo->sdir = kobject_get(bo->sdir);
+ if (!bo->sdir)
+ return 0;
+
+ bo->hdev = kobject_get(bo->sdir->parent);
+ if (!bo->hdev)
+ goto fail_put_sdir;
+
+ bo->sdev = bdev_get_kobj(bdev);
+ if (!bo->sdev)
+ goto fail_put_hdev;
+
+ bo->hdir = bdev_get_holder(bdev);
+ if (!bo->hdir)
+ goto fail_put_sdev;
+
+ return 1;
+
+fail_put_sdev:
+ kobject_put(bo->sdev);
+fail_put_hdev:
+ kobject_put(bo->hdev);
+fail_put_sdir:
+ kobject_put(bo->sdir);
+
+ return 0;
+}
+
+/* Put references of related kobjects at once. */
+static void bd_holder_release_dirs(struct bd_holder *bo)
+{
+ kobject_put(bo->hdir);
+ kobject_put(bo->sdev);
+ kobject_put(bo->hdev);
+ kobject_put(bo->sdir);
+}
+
+static struct bd_holder *alloc_bd_holder(struct kobject *kobj)
+{
+ struct bd_holder *bo;
+
+ bo = kzalloc(sizeof(*bo), GFP_KERNEL);
+ if (!bo)
+ return NULL;
+
+ bo->count = 1;
+ bo->sdir = kobj;
+
+ return bo;
+}
+
+static void free_bd_holder(struct bd_holder *bo)
+{
+ kfree(bo);
+}
+
+/**
+ * add_bd_holder - create sysfs symlinks for bd_claim() relationship
+ *
+ * @bdev: block device to be bd_claimed
+ * @bo: preallocated and initialized by alloc_bd_holder()
+ *
+ * If there is no matching entry with @bo in @bdev->bd_holder_list,
+ * add @bo to the list, create symlinks.
+ *
+ * Returns 1 if @bo was added to the list.
+ * Returns 0 if @bo wasn't used by any reason and should be freed.
+ */
+static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo)
+{
+ struct bd_holder *tmp;
+
+ if (!bo)
+ return 0;
+
+ list_for_each_entry(tmp, &bdev->bd_holder_list, list) {
+ if (tmp->sdir == bo->sdir) {
+ tmp->count++;
+ return 0;
+ }
+ }
+
+ if (!bd_holder_grab_dirs(bdev, bo))
+ return 0;
+
+ add_symlink(bo->sdir, bo->sdev);
+ add_symlink(bo->hdir, bo->hdev);
+ list_add_tail(&bo->list, &bdev->bd_holder_list);
+ return 1;
+}
+
+/**
+ * del_bd_holder - delete sysfs symlinks for bd_claim() relationship
+ *
+ * @bdev: block device to be bd_claimed
+ * @kobj: holder's kobject
+ *
+ * If there is matching entry with @kobj in @bdev->bd_holder_list
+ * and no other bd_claim() from the same kobject,
+ * remove the struct bd_holder from the list, delete symlinks for it.
+ *
+ * Returns a pointer to the struct bd_holder when it's removed from the list
+ * and ready to be freed.
+ * Returns NULL if matching claim isn't found or there is other bd_claim()
+ * by the same kobject.
+ */
+static struct bd_holder *del_bd_holder(struct block_device *bdev,
+ struct kobject *kobj)
+{
+ struct bd_holder *bo;
+
+ list_for_each_entry(bo, &bdev->bd_holder_list, list) {
+ if (bo->sdir == kobj) {
+ bo->count--;
+ BUG_ON(bo->count < 0);
+ if (!bo->count) {
+ list_del(&bo->list);
+ del_symlink(bo->sdir, bo->sdev);
+ del_symlink(bo->hdir, bo->hdev);
+ bd_holder_release_dirs(bo);
+ return bo;
+ }
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * bd_claim_by_kobject - bd_claim() with additional kobject signature
+ *
+ * @bdev: block device to be claimed
+ * @holder: holder's signature
+ * @kobj: holder's kobject
+ *
+ * Do bd_claim() and if it succeeds, create sysfs symlinks between
+ * the bdev and the holder's kobject.
+ * Use bd_release_from_kobject() when relesing the claimed bdev.
+ *
+ * Returns 0 on success. (same as bd_claim())
+ * Returns errno on failure.
+ */
+static int bd_claim_by_kobject(struct block_device *bdev, void *holder,
+ struct kobject *kobj)
+{
+ int res;
+ struct bd_holder *bo;
+
+ if (!kobj)
+ return -EINVAL;
+
+ bo = alloc_bd_holder(kobj);
+ if (!bo)
+ return -ENOMEM;
+
+ mutex_lock(&bdev->bd_mutex);
+ res = bd_claim(bdev, holder);
+ if (res || !add_bd_holder(bdev, bo))
+ free_bd_holder(bo);
+ mutex_unlock(&bdev->bd_mutex);
+
+ return res;
+}
+
+/**
+ * bd_release_from_kobject - bd_release() with additional kobject signature
+ *
+ * @bdev: block device to be released
+ * @kobj: holder's kobject
+ *
+ * Do bd_release() and remove sysfs symlinks created by bd_claim_by_kobject().
+ */
+static void bd_release_from_kobject(struct block_device *bdev,
+ struct kobject *kobj)
+{
+ struct bd_holder *bo;
+
+ if (!kobj)
+ return;
+
+ mutex_lock(&bdev->bd_mutex);
+ bd_release(bdev);
+ if ((bo = del_bd_holder(bdev, kobj)))
+ free_bd_holder(bo);
+ mutex_unlock(&bdev->bd_mutex);
+}
+
+/**
+ * bd_claim_by_disk - wrapper function for bd_claim_by_kobject()
+ *
+ * @bdev: block device to be claimed
+ * @holder: holder's signature
+ * @disk: holder's gendisk
+ *
+ * Call bd_claim_by_kobject() with getting @disk->slave_dir.
+ */
+int bd_claim_by_disk(struct block_device *bdev, void *holder,
+ struct gendisk *disk)
+{
+ return bd_claim_by_kobject(bdev, holder, kobject_get(disk->slave_dir));
+}
+EXPORT_SYMBOL_GPL(bd_claim_by_disk);
+
+/**
+ * bd_release_from_disk - wrapper function for bd_release_from_kobject()
+ *
+ * @bdev: block device to be claimed
+ * @disk: holder's gendisk
+ *
+ * Call bd_release_from_kobject() and put @disk->slave_dir.
+ */
+void bd_release_from_disk(struct block_device *bdev, struct gendisk *disk)
+{
+ bd_release_from_kobject(bdev, disk->slave_dir);
+ kobject_put(disk->slave_dir);
+}
+EXPORT_SYMBOL_GPL(bd_release_from_disk);
+#endif
+
/*
* Tries to open block device by device number. Use it ONLY if you
* really do not have anything better - i.e. when you are behind a
@@ -790,7 +1087,7 @@ struct address_space_operations def_blk_aops = {
.direct_IO = blkdev_direct_IO,
};
-struct file_operations def_blk_fops = {
+const struct file_operations def_blk_fops = {
.open = blkdev_open,
.release = blkdev_close,
.llseek = block_llseek,
diff --git a/fs/buffer.c b/fs/buffer.c
index d597758dd129..23f1f3a68077 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -493,7 +493,7 @@ static void free_more_memory(void)
wakeup_pdflush(1024);
yield();
- for_each_pgdat(pgdat) {
+ for_each_online_pgdat(pgdat) {
zones = pgdat->node_zonelists[gfp_zone(GFP_NOFS)].zones;
if (*zones)
try_to_free_pages(zones, GFP_NOFS);
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 8c6eb04d31e2..4e1b849f912f 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -250,7 +250,7 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
}
int register_chrdev(unsigned int major, const char *name,
- struct file_operations *fops)
+ const struct file_operations *fops)
{
struct char_device_struct *cd;
struct cdev *cdev;
@@ -406,7 +406,7 @@ static void cdev_purge(struct cdev *cdev)
* is contain the open that then fills in the correct operations
* depending on the special file...
*/
-struct file_operations def_chr_fops = {
+const struct file_operations def_chr_fops = {
.open = chrdev_open,
};
@@ -473,7 +473,7 @@ struct cdev *cdev_alloc(void)
return p;
}
-void cdev_init(struct cdev *cdev, struct file_operations *fops)
+void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 6b99b51d6694..4bbc544857bc 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -583,7 +583,7 @@ struct inode_operations cifs_symlink_inode_ops = {
#endif
};
-struct file_operations cifs_file_ops = {
+const struct file_operations cifs_file_ops = {
.read = do_sync_read,
.write = do_sync_write,
.readv = generic_file_readv,
@@ -607,7 +607,7 @@ struct file_operations cifs_file_ops = {
#endif /* CONFIG_CIFS_EXPERIMENTAL */
};
-struct file_operations cifs_file_direct_ops = {
+const struct file_operations cifs_file_direct_ops = {
/* no mmap, no aio, no readv -
BB reevaluate whether they can be done with directio, no cache */
.read = cifs_user_read,
@@ -626,7 +626,7 @@ struct file_operations cifs_file_direct_ops = {
.dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
};
-struct file_operations cifs_file_nobrl_ops = {
+const struct file_operations cifs_file_nobrl_ops = {
.read = do_sync_read,
.write = do_sync_write,
.readv = generic_file_readv,
@@ -649,7 +649,7 @@ struct file_operations cifs_file_nobrl_ops = {
#endif /* CONFIG_CIFS_EXPERIMENTAL */
};
-struct file_operations cifs_file_direct_nobrl_ops = {
+const struct file_operations cifs_file_direct_nobrl_ops = {
/* no mmap, no aio, no readv -
BB reevaluate whether they can be done with directio, no cache */
.read = cifs_user_read,
@@ -668,7 +668,7 @@ struct file_operations cifs_file_direct_nobrl_ops = {
#endif /* CONFIG_CIFS_EXPERIMENTAL */
};
-struct file_operations cifs_dir_ops = {
+const struct file_operations cifs_dir_ops = {
.readdir = cifs_readdir,
.release = cifs_closedir,
.read = generic_read_dir,
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 821a8eb22559..74f405ae4da3 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -61,10 +61,10 @@ extern struct inode_operations cifs_file_inode_ops;
extern struct inode_operations cifs_symlink_inode_ops;
/* Functions related to files and directories */
-extern struct file_operations cifs_file_ops;
-extern struct file_operations cifs_file_direct_ops; /* if directio mount */
-extern struct file_operations cifs_file_nobrl_ops;
-extern struct file_operations cifs_file_direct_nobrl_ops; /* if directio mount */
+extern const struct file_operations cifs_file_ops;
+extern const struct file_operations cifs_file_direct_ops; /* if directio mount */
+extern const struct file_operations cifs_file_nobrl_ops;
+extern const struct file_operations cifs_file_direct_nobrl_ops; /* if directio mount */
extern int cifs_open(struct inode *inode, struct file *file);
extern int cifs_close(struct inode *inode, struct file *file);
extern int cifs_closedir(struct inode *inode, struct file *file);
@@ -76,7 +76,7 @@ extern int cifs_lock(struct file *, int, struct file_lock *);
extern int cifs_fsync(struct file *, struct dentry *, int);
extern int cifs_flush(struct file *);
extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
-extern struct file_operations cifs_dir_ops;
+extern const struct file_operations cifs_dir_ops;
extern int cifs_dir_open(struct inode *inode, struct file *file);
extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
extern int cifs_dir_notify(struct file *, unsigned long arg);
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 54f76de8a686..71f2ea632e53 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -82,7 +82,7 @@ struct inode_operations coda_dir_inode_operations =
.setattr = coda_setattr,
};
-struct file_operations coda_dir_operations = {
+const struct file_operations coda_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = coda_readdir,
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 146a991d6eb5..7c2642431fa5 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -288,7 +288,7 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
return err;
}
-struct file_operations coda_file_operations = {
+const struct file_operations coda_file_operations = {
.llseek = generic_file_llseek,
.read = coda_file_read,
.write = coda_file_write,
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index 127714936c66..214822be87bd 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -36,7 +36,7 @@ struct inode_operations coda_ioctl_inode_operations =
.setattr = coda_setattr,
};
-struct file_operations coda_ioctl_operations = {
+const struct file_operations coda_ioctl_operations = {
.owner = THIS_MODULE,
.ioctl = coda_pioctl,
};
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index 98c74fe2e139..6c6771db36da 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -342,7 +342,7 @@ static int coda_psdev_release(struct inode * inode, struct file * file)
}
-static struct file_operations coda_psdev_fops = {
+static const struct file_operations coda_psdev_fops = {
.owner = THIS_MODULE,
.read = coda_psdev_read,
.write = coda_psdev_write,
diff --git a/fs/compat.c b/fs/compat.c
index ef5a0771592d..7f8e26ea427c 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1639,15 +1639,6 @@ void compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
* This is a virtual copy of sys_select from fs/select.c and probably
* should be compared to it from time to time
*/
-static void *select_bits_alloc(int size)
-{
- return kmalloc(6 * size, GFP_KERNEL);
-}
-
-static void select_bits_free(void *bits, int size)
-{
- kfree(bits);
-}
/*
* We can actually return ERESTARTSYS instead of EINTR, but I'd
@@ -1686,7 +1677,7 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp,
*/
ret = -ENOMEM;
size = FDS_BYTES(n);
- bits = select_bits_alloc(size);
+ bits = kmalloc(6 * size, GFP_KERNEL);
if (!bits)
goto out_nofds;
fds.in = (unsigned long *) bits;
@@ -1720,7 +1711,7 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp,
compat_set_fd_set(n, exp, fds.res_ex);
out:
- select_bits_free(bits, size);
+ kfree(bits);
out_nofds:
return ret;
}
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h
index f70e46951b37..3f4ff7a242b9 100644
--- a/fs/configfs/configfs_internal.h
+++ b/fs/configfs/configfs_internal.h
@@ -72,9 +72,9 @@ extern void configfs_release_fs(void);
extern struct rw_semaphore configfs_rename_sem;
extern struct super_block * configfs_sb;
-extern struct file_operations configfs_dir_operations;
-extern struct file_operations configfs_file_operations;
-extern struct file_operations bin_fops;
+extern const struct file_operations configfs_dir_operations;
+extern const struct file_operations configfs_file_operations;
+extern const struct file_operations bin_fops;
extern struct inode_operations configfs_dir_inode_operations;
extern struct inode_operations configfs_symlink_inode_operations;
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index ca60e3abef45..8ed9b06a9828 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -1027,7 +1027,7 @@ static loff_t configfs_dir_lseek(struct file * file, loff_t offset, int origin)
return offset;
}
-struct file_operations configfs_dir_operations = {
+const struct file_operations configfs_dir_operations = {
.open = configfs_dir_open,
.release = configfs_dir_close,
.llseek = configfs_dir_lseek,
diff --git a/fs/configfs/file.c b/fs/configfs/file.c
index 3921920d8716..f499803743e0 100644
--- a/fs/configfs/file.c
+++ b/fs/configfs/file.c
@@ -322,7 +322,7 @@ static int configfs_release(struct inode * inode, struct file * filp)
return 0;
}
-struct file_operations configfs_file_operations = {
+const struct file_operations configfs_file_operations = {
.read = configfs_read_file,
.write = configfs_write_file,
.llseek = generic_file_llseek,
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index acc1b2c10a86..9efcc3a164e8 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -29,7 +29,7 @@
static struct super_operations cramfs_ops;
static struct inode_operations cramfs_dir_inode_operations;
-static struct file_operations cramfs_directory_operations;
+static const struct file_operations cramfs_directory_operations;
static struct address_space_operations cramfs_aops;
static DEFINE_MUTEX(read_mutex);
@@ -512,7 +512,7 @@ static struct address_space_operations cramfs_aops = {
/*
* A directory can only readdir
*/
-static struct file_operations cramfs_directory_operations = {
+static const struct file_operations cramfs_directory_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = cramfs_readdir,
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 40c4fc973fad..66a505422e5c 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -39,7 +39,7 @@ static int default_open(struct inode *inode, struct file *file)
return 0;
}
-struct file_operations debugfs_file_operations = {
+const struct file_operations debugfs_file_operations = {
.read = default_read_file,
.write = default_write_file,
.open = default_open,
@@ -213,7 +213,7 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf,
return count;
}
-static struct file_operations fops_bool = {
+static const struct file_operations fops_bool = {
.read = read_file_bool,
.write = write_file_bool,
.open = default_open,
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index d4f1a2cddd47..85d166cdcae4 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -191,7 +191,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode,
*/
struct dentry *debugfs_create_file(const char *name, mode_t mode,
struct dentry *parent, void *data,
- struct file_operations *fops)
+ const struct file_operations *fops)
{
struct dentry *dentry = NULL;
int error;
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
index b621521e09d4..52f5059c4f31 100644
--- a/fs/devfs/base.c
+++ b/fs/devfs/base.c
@@ -856,14 +856,14 @@ 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 struct file_operations stat_fops = {
+static const struct file_operations stat_fops = {
.open = nonseekable_open,
.read = stat_read,
};
#endif
/* Devfs daemon file operations */
-static struct file_operations devfsd_fops = {
+static const struct file_operations devfsd_fops = {
.open = nonseekable_open,
.read = devfsd_read,
.ioctl = devfsd_ioctl,
@@ -1842,8 +1842,8 @@ static int try_modload(struct devfs_entry *parent, struct fs_info *fs_info,
static struct inode_operations devfs_iops;
static struct inode_operations devfs_dir_iops;
-static struct file_operations devfs_fops;
-static struct file_operations devfs_dir_fops;
+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)
@@ -2061,11 +2061,11 @@ static int devfs_open(struct inode *inode, struct file *file)
return err;
} /* End Function devfs_open */
-static struct file_operations devfs_fops = {
+static const struct file_operations devfs_fops = {
.open = devfs_open,
};
-static struct file_operations devfs_dir_fops = {
+static const struct file_operations devfs_dir_fops = {
.read = generic_read_dir,
.readdir = devfs_readdir,
};
diff --git a/fs/efs/dir.c b/fs/efs/dir.c
index 777c614ff360..17f5b2d3c16a 100644
--- a/fs/efs/dir.c
+++ b/fs/efs/dir.c
@@ -10,7 +10,7 @@
static int efs_readdir(struct file *, void *, filldir_t);
-struct file_operations efs_dir_operations = {
+const struct file_operations efs_dir_operations = {
.read = generic_read_dir,
.readdir = efs_readdir,
};
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index e067a06c6464..242fe1a66ce5 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -290,7 +290,7 @@ static kmem_cache_t *pwq_cache __read_mostly;
static struct vfsmount *eventpoll_mnt __read_mostly;
/* File callbacks that implement the eventpoll file behaviour */
-static struct file_operations eventpoll_fops = {
+static const struct file_operations eventpoll_fops = {
.release = ep_eventpoll_close,
.poll = ep_eventpoll_poll
};
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 0165388c425c..d672aa9f4061 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -658,7 +658,7 @@ not_empty:
return 0;
}
-struct file_operations ext2_dir_operations = {
+const struct file_operations ext2_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = ext2_readdir,
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 11035ac7986f..9f74a62be555 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -154,12 +154,12 @@ extern void ext2_write_super (struct super_block *);
*/
/* dir.c */
-extern struct file_operations ext2_dir_operations;
+extern const struct file_operations ext2_dir_operations;
/* file.c */
extern struct inode_operations ext2_file_inode_operations;
-extern struct file_operations ext2_file_operations;
-extern struct file_operations ext2_xip_file_operations;
+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;
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index a484412fc782..509cceca04db 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -39,7 +39,7 @@ static int ext2_release_file (struct inode * inode, struct file * filp)
* We have mostly NULL's here: the current defaults are ok for
* the ext2 filesystem.
*/
-struct file_operations ext2_file_operations = {
+const struct file_operations ext2_file_operations = {
.llseek = generic_file_llseek,
.read = generic_file_read,
.write = generic_file_write,
@@ -56,7 +56,7 @@ struct file_operations ext2_file_operations = {
};
#ifdef CONFIG_EXT2_FS_XIP
-struct file_operations ext2_xip_file_operations = {
+const struct file_operations ext2_xip_file_operations = {
.llseek = generic_file_llseek,
.read = xip_file_read,
.write = xip_file_write,
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index 38bd3f6ec147..f37528ed222e 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -39,7 +39,7 @@ static int ext3_dx_readdir(struct file * filp,
static int ext3_release_dir (struct inode * inode,
struct file * filp);
-struct file_operations ext3_dir_operations = {
+const struct file_operations ext3_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = ext3_readdir, /* we take BKL. needed?*/
diff --git a/fs/ext3/file.c b/fs/ext3/file.c
index 59098ea56711..783a796220bb 100644
--- a/fs/ext3/file.c
+++ b/fs/ext3/file.c
@@ -105,7 +105,7 @@ force_commit:
return ret;
}
-struct file_operations ext3_file_operations = {
+const struct file_operations ext3_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 4095bc149eb1..698b85bb1dd4 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -741,7 +741,7 @@ static int fat_dir_ioctl(struct inode * inode, struct file * filp,
return ret;
}
-struct file_operations fat_dir_operations = {
+const struct file_operations fat_dir_operations = {
.read = generic_read_dir,
.readdir = fat_readdir,
.ioctl = fat_dir_ioctl,
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 88aa1ae13f9f..1ee25232e6af 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -112,7 +112,7 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
}
}
-struct file_operations fat_file_operations = {
+const struct file_operations fat_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 404bfc9f7385..c1ce284f8a94 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -1435,9 +1435,6 @@ out_fail:
EXPORT_SYMBOL_GPL(fat_fill_super);
-int __init fat_cache_init(void);
-void fat_cache_destroy(void);
-
static int __init init_fat_fs(void)
{
int err;
diff --git a/fs/fifo.c b/fs/fifo.c
index d13fcd3ec803..889f722ee36d 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -145,6 +145,6 @@ err_nocleanup:
* is contain the open that then fills in the correct operations
* depending on the access mode of the file...
*/
-struct file_operations def_fifo_fops = {
+const struct file_operations def_fifo_fops = {
.open = fifo_open, /* will set read or write pipe_fops */
};
diff --git a/fs/file.c b/fs/file.c
index bbc743314730..55f4e7022563 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -373,6 +373,6 @@ static void __devinit fdtable_defer_list_init(int cpu)
void __init files_defer_init(void)
{
int i;
- for_each_cpu(i)
+ for_each_possible_cpu(i)
fdtable_defer_list_init(i);
}
diff --git a/fs/freevxfs/vxfs_extern.h b/fs/freevxfs/vxfs_extern.h
index 927acf70c591..1cf1fe8466a2 100644
--- a/fs/freevxfs/vxfs_extern.h
+++ b/fs/freevxfs/vxfs_extern.h
@@ -63,7 +63,7 @@ extern void vxfs_clear_inode(struct inode *);
/* vxfs_lookup.c */
extern struct inode_operations vxfs_dir_inode_ops;
-extern struct file_operations vxfs_dir_operations;
+extern const struct file_operations vxfs_dir_operations;
/* vxfs_olt.c */
extern int vxfs_read_olt(struct super_block *, u_long);
diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c
index 554eb455722c..29cce456c7ce 100644
--- a/fs/freevxfs/vxfs_lookup.c
+++ b/fs/freevxfs/vxfs_lookup.c
@@ -56,7 +56,7 @@ struct inode_operations vxfs_dir_inode_ops = {
.lookup = vxfs_lookup,
};
-struct file_operations vxfs_dir_operations = {
+const struct file_operations vxfs_dir_operations = {
.readdir = vxfs_readdir,
};
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 0c9a2ee54c91..23d1f52eb1b8 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -922,7 +922,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file)
return 0;
}
-struct file_operations fuse_dev_operations = {
+const struct file_operations fuse_dev_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = fuse_dev_read,
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index c72a8a97935c..256355b80256 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1170,7 +1170,7 @@ static struct inode_operations fuse_dir_inode_operations = {
.removexattr = fuse_removexattr,
};
-static struct file_operations fuse_dir_operations = {
+static const struct file_operations fuse_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = fuse_readdir,
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 6f05379b0a0d..975f2697e866 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -12,7 +12,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
-static struct file_operations fuse_direct_io_file_operations;
+static const struct file_operations fuse_direct_io_file_operations;
static int fuse_send_open(struct inode *inode, struct file *file, int isdir,
struct fuse_open_out *outargp)
@@ -611,7 +611,7 @@ static int fuse_set_page_dirty(struct page *page)
return 0;
}
-static struct file_operations fuse_file_operations = {
+static const struct file_operations fuse_file_operations = {
.llseek = generic_file_llseek,
.read = generic_file_read,
.write = generic_file_write,
@@ -623,7 +623,7 @@ static struct file_operations fuse_file_operations = {
.sendfile = generic_file_sendfile,
};
-static struct file_operations fuse_direct_io_file_operations = {
+static const struct file_operations fuse_direct_io_file_operations = {
.llseek = generic_file_llseek,
.read = fuse_direct_read,
.write = fuse_direct_write,
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 4a83adfec968..a16a04fcf41e 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -346,7 +346,7 @@ static inline u64 get_node_id(struct inode *inode)
}
/** Device operations */
-extern struct file_operations fuse_dev_operations;
+extern const struct file_operations fuse_dev_operations;
/**
* This is the single global spinlock which protects FUSE's structures
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index 534e5a7480ef..7cd8cc03aea7 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -313,7 +313,7 @@ static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
return res;
}
-struct file_operations hfs_dir_operations = {
+const struct file_operations hfs_dir_operations = {
.read = generic_read_dir,
.readdir = hfs_readdir,
.llseek = generic_file_llseek,
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
index 18ce47ab1b71..3ed8663a8db1 100644
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -169,7 +169,7 @@ extern int hfs_cat_move(u32, struct inode *, struct qstr *,
extern void hfs_cat_build_key(struct super_block *, btree_key *, u32, struct qstr *);
/* dir.c */
-extern struct file_operations hfs_dir_operations;
+extern const struct file_operations hfs_dir_operations;
extern struct inode_operations hfs_dir_inode_operations;
/* extent.c */
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 2c564701724f..2d4ced22201b 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -17,7 +17,7 @@
#include "hfs_fs.h"
#include "btree.h"
-static struct file_operations hfs_file_operations;
+static const struct file_operations hfs_file_operations;
static struct inode_operations hfs_file_inode_operations;
/*================ Variable-like macros ================*/
@@ -601,7 +601,7 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)
}
-static struct file_operations hfs_file_operations = {
+static const struct file_operations hfs_file_operations = {
.llseek = generic_file_llseek,
.read = generic_file_read,
.write = generic_file_write,
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 01a6fe3a395c..1f9ece0de326 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -483,7 +483,7 @@ struct inode_operations hfsplus_dir_inode_operations = {
.rename = hfsplus_rename,
};
-struct file_operations hfsplus_dir_operations = {
+const struct file_operations hfsplus_dir_operations = {
.read = generic_read_dir,
.readdir = hfsplus_readdir,
.ioctl = hfsplus_ioctl,
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 9fbe4d2aeece..acf66dba3e01 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -280,7 +280,7 @@ static struct inode_operations hfsplus_file_inode_operations = {
.listxattr = hfsplus_listxattr,
};
-static struct file_operations hfsplus_file_operations = {
+static const struct file_operations hfsplus_file_operations = {
.llseek = generic_file_llseek,
.read = generic_file_read,
.write = generic_file_write,
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index b3ad0bd0312f..bf0f8e16e433 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -384,7 +384,7 @@ int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
}
-static struct file_operations hostfs_file_fops = {
+static const struct file_operations hostfs_file_fops = {
.llseek = generic_file_llseek,
.read = generic_file_read,
.sendfile = generic_file_sendfile,
@@ -399,7 +399,7 @@ static struct file_operations hostfs_file_fops = {
.fsync = hostfs_fsync,
};
-static struct file_operations hostfs_dir_fops = {
+static const struct file_operations hostfs_dir_fops = {
.llseek = generic_file_llseek,
.readdir = hostfs_readdir,
.read = generic_read_dir,
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
index b97809deba66..23b7cee72123 100644
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -360,7 +360,6 @@ int do_statfs(char *root, long *bsize_out, long long *blocks_out,
spare_out[2] = buf.f_spare[2];
spare_out[3] = buf.f_spare[3];
spare_out[4] = buf.f_spare[4];
- spare_out[5] = buf.f_spare[5];
return(0);
}
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
index 5591f9623aa2..ecc9180645ae 100644
--- a/fs/hpfs/dir.c
+++ b/fs/hpfs/dir.c
@@ -310,7 +310,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name
return ERR_PTR(-ENOENT);
}
-struct file_operations hpfs_dir_ops =
+const struct file_operations hpfs_dir_ops =
{
.llseek = hpfs_dir_lseek,
.read = generic_read_dir,
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index 7c995ac4081b..d3b9fffe45a1 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -119,7 +119,7 @@ static ssize_t hpfs_file_write(struct file *file, const char __user *buf,
return retval;
}
-struct file_operations hpfs_file_ops =
+const struct file_operations hpfs_file_ops =
{
.llseek = generic_file_llseek,
.read = generic_file_read,
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
index 4c6473ab3b34..29b7a3e55173 100644
--- a/fs/hpfs/hpfs_fn.h
+++ b/fs/hpfs/hpfs_fn.h
@@ -240,7 +240,7 @@ void hpfs_set_dentry_operations(struct dentry *);
/* dir.c */
struct dentry *hpfs_lookup(struct inode *, struct dentry *, struct nameidata *);
-extern struct file_operations hpfs_dir_ops;
+extern const struct file_operations hpfs_dir_ops;
/* dnode.c */
@@ -266,7 +266,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, char *, char *, int);
/* file.c */
int hpfs_file_fsync(struct file *, struct dentry *, int);
-extern struct file_operations hpfs_file_ops;
+extern const struct file_operations hpfs_file_ops;
extern struct inode_operations hpfs_file_iops;
extern struct address_space_operations hpfs_aops;
diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
index a44dc5897399..2ba20cdb5baa 100644
--- a/fs/hppfs/hppfs_kern.c
+++ b/fs/hppfs/hppfs_kern.c
@@ -558,7 +558,7 @@ static loff_t hppfs_llseek(struct file *file, loff_t off, int where)
return(default_llseek(file, off, where));
}
-static struct file_operations hppfs_file_fops = {
+static const struct file_operations hppfs_file_fops = {
.owner = NULL,
.llseek = hppfs_llseek,
.read = hppfs_read,
@@ -609,7 +609,7 @@ static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync)
return(0);
}
-static struct file_operations hppfs_dir_fops = {
+static const struct file_operations hppfs_dir_fops = {
.owner = NULL,
.readdir = hppfs_readdir,
.open = hppfs_dir_open,
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 25fa8bba8cb5..3a5b4e923455 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -35,7 +35,7 @@
static struct super_operations hugetlbfs_ops;
static struct address_space_operations hugetlbfs_aops;
-struct file_operations hugetlbfs_file_operations;
+const struct file_operations hugetlbfs_file_operations;
static struct inode_operations hugetlbfs_dir_inode_operations;
static struct inode_operations hugetlbfs_inode_operations;
@@ -566,7 +566,7 @@ static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
inode_init_once(&ei->vfs_inode);
}
-struct file_operations hugetlbfs_file_operations = {
+const struct file_operations hugetlbfs_file_operations = {
.mmap = hugetlbfs_file_mmap,
.fsync = simple_sync_file,
.get_unmapped_area = hugetlb_get_unmapped_area,
diff --git a/fs/inode.c b/fs/inode.c
index 1fddf2803af8..32b7c3375021 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -104,7 +104,7 @@ static struct inode *alloc_inode(struct super_block *sb)
{
static struct address_space_operations empty_aops;
static struct inode_operations empty_iops;
- static struct file_operations empty_fops;
+ static const struct file_operations empty_fops;
struct inode *inode;
if (sb->s_op->alloc_inode)
diff --git a/fs/inotify.c b/fs/inotify.c
index f48a3dae0712..367c487c014b 100644
--- a/fs/inotify.c
+++ b/fs/inotify.c
@@ -920,7 +920,7 @@ static long inotify_ioctl(struct file *file, unsigned int cmd,
return ret;
}
-static struct file_operations inotify_fops = {
+static const struct file_operations inotify_fops = {
.poll = inotify_poll,
.read = inotify_read,
.release = inotify_release,
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 7901ac9f97ab..5440ea292c69 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -16,7 +16,7 @@
static int isofs_readdir(struct file *, void *, filldir_t);
-struct file_operations isofs_dir_operations =
+const struct file_operations isofs_dir_operations =
{
.read = generic_read_dir,
.readdir = isofs_readdir,
diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h
index 439a19b1bf3e..b87ba066f5e7 100644
--- a/fs/isofs/isofs.h
+++ b/fs/isofs/isofs.h
@@ -175,6 +175,6 @@ isofs_normalize_block_and_offset(struct iso_directory_record* de,
}
extern struct inode_operations isofs_dir_inode_operations;
-extern struct file_operations isofs_dir_operations;
+extern const struct file_operations isofs_dir_operations;
extern struct address_space_operations isofs_symlink_aops;
extern struct export_operations isofs_export_ops;
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
index 5a4519e834da..020cc097c539 100644
--- a/fs/jffs/inode-v23.c
+++ b/fs/jffs/inode-v23.c
@@ -55,9 +55,9 @@
static int jffs_remove(struct inode *dir, struct dentry *dentry, int type);
static struct super_operations jffs_ops;
-static struct file_operations jffs_file_operations;
+static const struct file_operations jffs_file_operations;
static struct inode_operations jffs_file_inode_operations;
-static struct file_operations jffs_dir_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;
@@ -1629,7 +1629,7 @@ static int jffs_fsync(struct file *f, struct dentry *d, int datasync)
}
-static struct file_operations jffs_file_operations =
+static const struct file_operations jffs_file_operations =
{
.open = generic_file_open,
.llseek = generic_file_llseek,
@@ -1649,7 +1649,7 @@ static struct inode_operations jffs_file_inode_operations =
};
-static struct file_operations jffs_dir_operations =
+static const struct file_operations jffs_dir_operations =
{
.readdir = jffs_readdir,
};
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index a7bf9cb2567f..8bc7a5018e40 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -37,7 +37,7 @@ static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t);
static int jffs2_rename (struct inode *, struct dentry *,
struct inode *, struct dentry *);
-struct file_operations jffs2_dir_operations =
+const struct file_operations jffs2_dir_operations =
{
.read = generic_read_dir,
.readdir = jffs2_readdir,
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index 935f273dc57b..9f4171213e58 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -38,7 +38,7 @@ int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync)
return 0;
}
-struct file_operations jffs2_file_operations =
+const struct file_operations jffs2_file_operations =
{
.llseek = generic_file_llseek,
.open = generic_file_open,
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index 59e7a393200c..d307cf548625 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -159,11 +159,11 @@ void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c);
void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c);
/* dir.c */
-extern struct file_operations jffs2_dir_operations;
+extern const struct file_operations jffs2_dir_operations;
extern struct inode_operations jffs2_dir_inode_operations;
/* file.c */
-extern struct file_operations jffs2_file_operations;
+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;
int jffs2_fsync(struct file *, struct dentry *, int);
diff --git a/fs/jfs/file.c b/fs/jfs/file.c
index e1ac6e497e2b..1c9745be5ada 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -100,7 +100,7 @@ struct inode_operations jfs_file_inode_operations = {
#endif
};
-struct file_operations jfs_file_operations = {
+const struct file_operations jfs_file_operations = {
.open = jfs_open,
.llseek = generic_file_llseek,
.write = generic_file_write,
diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h
index 095d471b9f9a..c30072674464 100644
--- a/fs/jfs/jfs_inode.h
+++ b/fs/jfs/jfs_inode.h
@@ -35,9 +35,9 @@ extern void jfs_set_inode_flags(struct inode *);
extern struct address_space_operations jfs_aops;
extern struct inode_operations jfs_dir_inode_operations;
-extern struct file_operations jfs_dir_operations;
+extern const struct file_operations jfs_dir_operations;
extern struct inode_operations jfs_file_inode_operations;
-extern struct file_operations jfs_file_operations;
+extern const struct file_operations jfs_file_operations;
extern struct inode_operations jfs_symlink_inode_operations;
extern struct dentry_operations jfs_ci_dentry_operations;
#endif /* _H_JFS_INODE */
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 309cee575f7d..09ea03f62277 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -1519,7 +1519,7 @@ struct inode_operations jfs_dir_inode_operations = {
#endif
};
-struct file_operations jfs_dir_operations = {
+const struct file_operations jfs_dir_operations = {
.read = generic_read_dir,
.readdir = jfs_readdir,
.fsync = jfs_fsync,
diff --git a/fs/libfs.c b/fs/libfs.c
index 4fdeaceb892c..7145ba7a48d0 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -179,7 +179,7 @@ ssize_t generic_read_dir(struct file *filp, char __user *buf, size_t siz, loff_t
return -EISDIR;
}
-struct file_operations simple_dir_operations = {
+const struct file_operations simple_dir_operations = {
.open = dcache_dir_open,
.release = dcache_dir_close,
.llseek = dcache_dir_lseek,
diff --git a/fs/mbcache.c b/fs/mbcache.c
index 73e754fea2d8..e4fde1ab22cd 100644
--- a/fs/mbcache.c
+++ b/fs/mbcache.c
@@ -311,7 +311,7 @@ fail:
/*
* mb_cache_shrink()
*
- * Removes all cache entires of a device from the cache. All cache entries
+ * Removes all cache entries of a device from the cache. All cache entries
* currently in use cannot be freed, and thus remain in the cache. All others
* are freed.
*
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 732502aabc05..69224d1fe043 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -14,7 +14,7 @@ typedef struct minix_dir_entry minix_dirent;
static int minix_readdir(struct file *, void *, filldir_t);
-struct file_operations minix_dir_operations = {
+const struct file_operations minix_dir_operations = {
.read = generic_read_dir,
.readdir = minix_readdir,
.fsync = minix_sync_file,
diff --git a/fs/minix/file.c b/fs/minix/file.c
index f1d77acb3f01..420b32882a10 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -15,7 +15,7 @@
*/
int minix_sync_file(struct file *, struct dentry *, int);
-struct file_operations minix_file_operations = {
+const struct file_operations minix_file_operations = {
.llseek = generic_file_llseek,
.read = generic_file_read,
.write = generic_file_write,
diff --git a/fs/minix/minix.h b/fs/minix/minix.h
index e42a8bb89001..c55b77cdcc8e 100644
--- a/fs/minix/minix.h
+++ b/fs/minix/minix.h
@@ -81,8 +81,8 @@ extern int minix_sync_file(struct file *, struct dentry *, int);
extern struct inode_operations minix_file_inode_operations;
extern struct inode_operations minix_dir_inode_operations;
-extern struct file_operations minix_file_operations;
-extern struct file_operations minix_dir_operations;
+extern const struct file_operations minix_file_operations;
+extern const struct file_operations minix_dir_operations;
extern struct dentry_operations minix_dentry_operations;
static inline struct minix_sb_info *minix_sb(struct super_block *sb)
diff --git a/fs/namei.c b/fs/namei.c
index 98dc2e134362..22f6e8d16aa8 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -546,6 +546,22 @@ struct path {
struct dentry *dentry;
};
+static inline void dput_path(struct path *path, struct nameidata *nd)
+{
+ dput(path->dentry);
+ if (path->mnt != nd->mnt)
+ mntput(path->mnt);
+}
+
+static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
+{
+ dput(nd->dentry);
+ if (nd->mnt != path->mnt)
+ mntput(nd->mnt);
+ nd->mnt = path->mnt;
+ nd->dentry = path->dentry;
+}
+
static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd)
{
int error;
@@ -555,8 +571,11 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata
touch_atime(path->mnt, dentry);
nd_set_link(nd, NULL);
- if (path->mnt == nd->mnt)
- mntget(path->mnt);
+ if (path->mnt != nd->mnt) {
+ path_to_nameidata(path, nd);
+ dget(dentry);
+ }
+ mntget(path->mnt);
cookie = dentry->d_inode->i_op->follow_link(dentry, nd);
error = PTR_ERR(cookie);
if (!IS_ERR(cookie)) {
@@ -573,22 +592,6 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata
return error;
}
-static inline void dput_path(struct path *path, struct nameidata *nd)
-{
- dput(path->dentry);
- if (path->mnt != nd->mnt)
- mntput(path->mnt);
-}
-
-static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
-{
- dput(nd->dentry);
- if (nd->mnt != path->mnt)
- mntput(nd->mnt);
- nd->mnt = path->mnt;
- nd->dentry = path->dentry;
-}
-
/*
* This limits recursive symlink follows to 8, while
* limiting consecutive symlinks to 40.
diff --git a/fs/namespace.c b/fs/namespace.c
index e069a4c5e389..bf478addb852 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -459,9 +459,9 @@ int may_umount_tree(struct vfsmount *mnt)
spin_unlock(&vfsmount_lock);
if (actual_refs > minimum_refs)
- return -EBUSY;
+ return 0;
- return 0;
+ return 1;
}
EXPORT_SYMBOL(may_umount_tree);
@@ -481,10 +481,10 @@ EXPORT_SYMBOL(may_umount_tree);
*/
int may_umount(struct vfsmount *mnt)
{
- int ret = 0;
+ int ret = 1;
spin_lock(&vfsmount_lock);
if (propagate_mount_busy(mnt, 2))
- ret = -EBUSY;
+ ret = 0;
spin_unlock(&vfsmount_lock);
return ret;
}
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index cfd76f431dc0..f0860c602d8b 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -49,7 +49,7 @@ extern int ncp_symlink(struct inode *, struct dentry *, const char *);
#define ncp_symlink NULL
#endif
-struct file_operations ncp_dir_operations =
+const struct file_operations ncp_dir_operations =
{
.read = generic_read_dir,
.readdir = ncp_readdir,
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index ebdad8f6398f..e6b7c67cf057 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -283,7 +283,7 @@ static int ncp_release(struct inode *inode, struct file *file) {
return 0;
}
-struct file_operations ncp_file_operations =
+const struct file_operations ncp_file_operations =
{
.llseek = remote_llseek,
.read = ncp_file_read,
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 06c48b385c94..a23f34894167 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -54,7 +54,7 @@ static int nfs_rename(struct inode *, struct dentry *,
static int nfs_fsync_dir(struct file *, struct dentry *, int);
static loff_t nfs_llseek_dir(struct file *, loff_t, int);
-struct file_operations nfs_dir_operations = {
+const struct file_operations nfs_dir_operations = {
.llseek = nfs_llseek_dir,
.read = generic_read_dir,
.readdir = nfs_readdir,
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index dee49a0cb995..f1df2c8d9259 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -49,7 +49,7 @@ static int nfs_check_flags(int flags);
static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
-struct file_operations nfs_file_operations = {
+const struct file_operations nfs_file_operations = {
.llseek = nfs_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 417ec02df44f..c340be0a3f59 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -57,27 +57,17 @@ static int exp_verify_string(char *cp, int max);
#define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1)
static struct cache_head *expkey_table[EXPKEY_HASHMAX];
-static inline int svc_expkey_hash(struct svc_expkey *item)
+static void expkey_put(struct kref *ref)
{
- int hash = item->ek_fsidtype;
- char * cp = (char*)item->ek_fsid;
- int len = key_len(item->ek_fsidtype);
+ struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
- hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
- hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
- return hash & EXPKEY_HASHMASK;
-}
-
-void expkey_put(struct cache_head *item, struct cache_detail *cd)
-{
- if (cache_put(item, cd)) {
- struct svc_expkey *key = container_of(item, struct svc_expkey, h);
- if (test_bit(CACHE_VALID, &item->flags) &&
- !test_bit(CACHE_NEGATIVE, &item->flags))
- exp_put(key->ek_export);
- auth_domain_put(key->ek_client);
- kfree(key);
+ if (test_bit(CACHE_VALID, &key->h.flags) &&
+ !test_bit(CACHE_NEGATIVE, &key->h.flags)) {
+ dput(key->ek_dentry);
+ mntput(key->ek_mnt);
}
+ auth_domain_put(key->ek_client);
+ kfree(key);
}
static void expkey_request(struct cache_detail *cd,
@@ -95,7 +85,10 @@ static void expkey_request(struct cache_detail *cd,
(*bpp)[-1] = '\n';
}
-static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *, int);
+static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old);
+static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *);
+static struct cache_detail svc_expkey_cache;
+
static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
{
/* client fsidtype fsid [path] */
@@ -106,6 +99,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
int fsidtype;
char *ep;
struct svc_expkey key;
+ struct svc_expkey *ek;
if (mesg[mlen-1] != '\n')
return -EINVAL;
@@ -150,40 +144,38 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
key.ek_fsidtype = fsidtype;
memcpy(key.ek_fsid, buf, len);
+ ek = svc_expkey_lookup(&key);
+ err = -ENOMEM;
+ if (!ek)
+ goto out;
+
/* now we want a pathname, or empty meaning NEGATIVE */
+ err = -EINVAL;
if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0)
goto out;
dprintk("Path seems to be <%s>\n", buf);
err = 0;
if (len == 0) {
- struct svc_expkey *ek;
set_bit(CACHE_NEGATIVE, &key.h.flags);
- ek = svc_expkey_lookup(&key, 1);
+ ek = svc_expkey_update(&key, ek);
if (ek)
- expkey_put(&ek->h, &svc_expkey_cache);
+ cache_put(&ek->h, &svc_expkey_cache);
+ else err = -ENOMEM;
} else {
struct nameidata nd;
- struct svc_expkey *ek;
- struct svc_export *exp;
err = path_lookup(buf, 0, &nd);
if (err)
goto out;
dprintk("Found the path %s\n", buf);
- exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
-
- err = -ENOENT;
- if (!exp)
- goto out_nd;
- key.ek_export = exp;
- dprintk("And found export\n");
+ key.ek_mnt = nd.mnt;
+ key.ek_dentry = nd.dentry;
- ek = svc_expkey_lookup(&key, 1);
+ ek = svc_expkey_update(&key, ek);
if (ek)
- expkey_put(&ek->h, &svc_expkey_cache);
- exp_put(exp);
- err = 0;
- out_nd:
+ cache_put(&ek->h, &svc_expkey_cache);
+ else
+ err = -ENOMEM;
path_release(&nd);
}
cache_flush();
@@ -214,35 +206,31 @@ static int expkey_show(struct seq_file *m,
if (test_bit(CACHE_VALID, &h->flags) &&
!test_bit(CACHE_NEGATIVE, &h->flags)) {
seq_printf(m, " ");
- seq_path(m, ek->ek_export->ex_mnt, ek->ek_export->ex_dentry, "\\ \t\n");
+ seq_path(m, ek->ek_mnt, ek->ek_dentry, "\\ \t\n");
}
seq_printf(m, "\n");
return 0;
}
-
-struct cache_detail svc_expkey_cache = {
- .owner = THIS_MODULE,
- .hash_size = EXPKEY_HASHMAX,
- .hash_table = expkey_table,
- .name = "nfsd.fh",
- .cache_put = expkey_put,
- .cache_request = expkey_request,
- .cache_parse = expkey_parse,
- .cache_show = expkey_show,
-};
-static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b)
+static inline int expkey_match (struct cache_head *a, struct cache_head *b)
{
- if (a->ek_fsidtype != b->ek_fsidtype ||
- a->ek_client != b->ek_client ||
- memcmp(a->ek_fsid, b->ek_fsid, key_len(a->ek_fsidtype)) != 0)
+ struct svc_expkey *orig = container_of(a, struct svc_expkey, h);
+ struct svc_expkey *new = container_of(b, struct svc_expkey, h);
+
+ if (orig->ek_fsidtype != new->ek_fsidtype ||
+ orig->ek_client != new->ek_client ||
+ memcmp(orig->ek_fsid, new->ek_fsid, key_len(orig->ek_fsidtype)) != 0)
return 0;
return 1;
}
-static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *item)
+static inline void expkey_init(struct cache_head *cnew,
+ struct cache_head *citem)
{
- cache_get(&item->ek_client->h);
+ struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
+ struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
+
+ kref_get(&item->ek_client->ref);
new->ek_client = item->ek_client;
new->ek_fsidtype = item->ek_fsidtype;
new->ek_fsid[0] = item->ek_fsid[0];
@@ -250,39 +238,94 @@ static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *it
new->ek_fsid[2] = item->ek_fsid[2];
}
-static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item)
+static inline void expkey_update(struct cache_head *cnew,
+ struct cache_head *citem)
+{
+ struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
+ struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
+
+ new->ek_mnt = mntget(item->ek_mnt);
+ new->ek_dentry = dget(item->ek_dentry);
+}
+
+static struct cache_head *expkey_alloc(void)
{
- cache_get(&item->ek_export->h);
- new->ek_export = item->ek_export;
+ struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL);
+ if (i)
+ return &i->h;
+ else
+ return NULL;
}
-static DefineSimpleCacheLookup(svc_expkey,0) /* no inplace updates */
+static struct cache_detail svc_expkey_cache = {
+ .owner = THIS_MODULE,
+ .hash_size = EXPKEY_HASHMAX,
+ .hash_table = expkey_table,
+ .name = "nfsd.fh",
+ .cache_put = expkey_put,
+ .cache_request = expkey_request,
+ .cache_parse = expkey_parse,
+ .cache_show = expkey_show,
+ .match = expkey_match,
+ .init = expkey_init,
+ .update = expkey_update,
+ .alloc = expkey_alloc,
+};
-#define EXPORT_HASHBITS 8
-#define EXPORT_HASHMAX (1<< EXPORT_HASHBITS)
-#define EXPORT_HASHMASK (EXPORT_HASHMAX -1)
+static struct svc_expkey *
+svc_expkey_lookup(struct svc_expkey *item)
+{
+ struct cache_head *ch;
+ int hash = item->ek_fsidtype;
+ char * cp = (char*)item->ek_fsid;
+ int len = key_len(item->ek_fsidtype);
-static struct cache_head *export_table[EXPORT_HASHMAX];
+ hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
+ hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
+ hash &= EXPKEY_HASHMASK;
-static inline int svc_export_hash(struct svc_export *item)
+ ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h,
+ hash);
+ if (ch)
+ return container_of(ch, struct svc_expkey, h);
+ else
+ return NULL;
+}
+
+static struct svc_expkey *
+svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old)
{
- int rv;
+ struct cache_head *ch;
+ int hash = new->ek_fsidtype;
+ char * cp = (char*)new->ek_fsid;
+ int len = key_len(new->ek_fsidtype);
- rv = hash_ptr(item->ex_client, EXPORT_HASHBITS);
- rv ^= hash_ptr(item->ex_dentry, EXPORT_HASHBITS);
- rv ^= hash_ptr(item->ex_mnt, EXPORT_HASHBITS);
- return rv;
+ hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
+ hash ^= hash_ptr(new->ek_client, EXPKEY_HASHBITS);
+ hash &= EXPKEY_HASHMASK;
+
+ ch = sunrpc_cache_update(&svc_expkey_cache, &new->h,
+ &old->h, hash);
+ if (ch)
+ return container_of(ch, struct svc_expkey, h);
+ else
+ return NULL;
}
-void svc_export_put(struct cache_head *item, struct cache_detail *cd)
+
+#define EXPORT_HASHBITS 8
+#define EXPORT_HASHMAX (1<< EXPORT_HASHBITS)
+#define EXPORT_HASHMASK (EXPORT_HASHMAX -1)
+
+static struct cache_head *export_table[EXPORT_HASHMAX];
+
+static void svc_export_put(struct kref *ref)
{
- if (cache_put(item, cd)) {
- struct svc_export *exp = container_of(item, struct svc_export, h);
- dput(exp->ex_dentry);
- mntput(exp->ex_mnt);
- auth_domain_put(exp->ex_client);
- kfree(exp);
- }
+ struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
+ dput(exp->ex_dentry);
+ mntput(exp->ex_mnt);
+ auth_domain_put(exp->ex_client);
+ kfree(exp);
}
static void svc_export_request(struct cache_detail *cd,
@@ -304,7 +347,9 @@ static void svc_export_request(struct cache_detail *cd,
(*bpp)[-1] = '\n';
}
-static struct svc_export *svc_export_lookup(struct svc_export *, int);
+static struct svc_export *svc_export_update(struct svc_export *new,
+ struct svc_export *old);
+static struct svc_export *svc_export_lookup(struct svc_export *);
static int check_export(struct inode *inode, int flags)
{
@@ -417,11 +462,16 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
if (err) goto out;
}
- expp = svc_export_lookup(&exp, 1);
+ expp = svc_export_lookup(&exp);
if (expp)
- exp_put(expp);
- err = 0;
+ expp = svc_export_update(&exp, expp);
+ else
+ err = -ENOMEM;
cache_flush();
+ if (expp == NULL)
+ err = -ENOMEM;
+ else
+ exp_put(expp);
out:
if (nd.dentry)
path_release(&nd);
@@ -455,6 +505,46 @@ static int svc_export_show(struct seq_file *m,
seq_puts(m, ")\n");
return 0;
}
+static int svc_export_match(struct cache_head *a, struct cache_head *b)
+{
+ struct svc_export *orig = container_of(a, struct svc_export, h);
+ struct svc_export *new = container_of(b, struct svc_export, h);
+ return orig->ex_client == new->ex_client &&
+ orig->ex_dentry == new->ex_dentry &&
+ orig->ex_mnt == new->ex_mnt;
+}
+
+static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
+{
+ struct svc_export *new = container_of(cnew, struct svc_export, h);
+ struct svc_export *item = container_of(citem, struct svc_export, h);
+
+ kref_get(&item->ex_client->ref);
+ new->ex_client = item->ex_client;
+ new->ex_dentry = dget(item->ex_dentry);
+ new->ex_mnt = mntget(item->ex_mnt);
+}
+
+static void export_update(struct cache_head *cnew, struct cache_head *citem)
+{
+ struct svc_export *new = container_of(cnew, struct svc_export, h);
+ struct svc_export *item = container_of(citem, struct svc_export, h);
+
+ new->ex_flags = item->ex_flags;
+ new->ex_anon_uid = item->ex_anon_uid;
+ new->ex_anon_gid = item->ex_anon_gid;
+ new->ex_fsid = item->ex_fsid;
+}
+
+static struct cache_head *svc_export_alloc(void)
+{
+ struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL);
+ if (i)
+ return &i->h;
+ else
+ return NULL;
+}
+
struct cache_detail svc_export_cache = {
.owner = THIS_MODULE,
.hash_size = EXPORT_HASHMAX,
@@ -464,34 +554,49 @@ struct cache_detail svc_export_cache = {
.cache_request = svc_export_request,
.cache_parse = svc_export_parse,
.cache_show = svc_export_show,
+ .match = svc_export_match,
+ .init = svc_export_init,
+ .update = export_update,
+ .alloc = svc_export_alloc,
};
-static inline int svc_export_match(struct svc_export *a, struct svc_export *b)
+static struct svc_export *
+svc_export_lookup(struct svc_export *exp)
{
- return a->ex_client == b->ex_client &&
- a->ex_dentry == b->ex_dentry &&
- a->ex_mnt == b->ex_mnt;
-}
-static inline void svc_export_init(struct svc_export *new, struct svc_export *item)
-{
- cache_get(&item->ex_client->h);
- new->ex_client = item->ex_client;
- new->ex_dentry = dget(item->ex_dentry);
- new->ex_mnt = mntget(item->ex_mnt);
+ struct cache_head *ch;
+ int hash;
+ hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS);
+ hash ^= hash_ptr(exp->ex_dentry, EXPORT_HASHBITS);
+ hash ^= hash_ptr(exp->ex_mnt, EXPORT_HASHBITS);
+
+ ch = sunrpc_cache_lookup(&svc_export_cache, &exp->h,
+ hash);
+ if (ch)
+ return container_of(ch, struct svc_export, h);
+ else
+ return NULL;
}
-static inline void svc_export_update(struct svc_export *new, struct svc_export *item)
+static struct svc_export *
+svc_export_update(struct svc_export *new, struct svc_export *old)
{
- new->ex_flags = item->ex_flags;
- new->ex_anon_uid = item->ex_anon_uid;
- new->ex_anon_gid = item->ex_anon_gid;
- new->ex_fsid = item->ex_fsid;
+ struct cache_head *ch;
+ int hash;
+ hash = hash_ptr(old->ex_client, EXPORT_HASHBITS);
+ hash ^= hash_ptr(old->ex_dentry, EXPORT_HASHBITS);
+ hash ^= hash_ptr(old->ex_mnt, EXPORT_HASHBITS);
+
+ ch = sunrpc_cache_update(&svc_export_cache, &new->h,
+ &old->h,
+ hash);
+ if (ch)
+ return container_of(ch, struct svc_export, h);
+ else
+ return NULL;
}
-static DefineSimpleCacheLookup(svc_export,1) /* allow inplace updates */
-
-struct svc_expkey *
+static struct svc_expkey *
exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
{
struct svc_expkey key, *ek;
@@ -504,7 +609,7 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
key.ek_fsidtype = fsid_type;
memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
- ek = svc_expkey_lookup(&key, 0);
+ ek = svc_expkey_lookup(&key);
if (ek != NULL)
if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp)))
ek = ERR_PTR(err);
@@ -519,13 +624,16 @@ static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv,
key.ek_client = clp;
key.ek_fsidtype = fsid_type;
memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
- key.ek_export = exp;
+ key.ek_mnt = exp->ex_mnt;
+ key.ek_dentry = exp->ex_dentry;
key.h.expiry_time = NEVER;
key.h.flags = 0;
- ek = svc_expkey_lookup(&key, 1);
+ ek = svc_expkey_lookup(&key);
+ if (ek)
+ ek = svc_expkey_update(&key,ek);
if (ek) {
- expkey_put(&ek->h, &svc_expkey_cache);
+ cache_put(&ek->h, &svc_expkey_cache);
return 0;
}
return -ENOMEM;
@@ -573,7 +681,7 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
key.ex_mnt = mnt;
key.ex_dentry = dentry;
- exp = svc_export_lookup(&key, 0);
+ exp = svc_export_lookup(&key);
if (exp != NULL)
switch (cache_check(&svc_export_cache, &exp->h, reqp)) {
case 0: break;
@@ -654,7 +762,7 @@ static void exp_fsid_unhash(struct svc_export *exp)
ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
if (ek && !IS_ERR(ek)) {
ek->h.expiry_time = get_seconds()-1;
- expkey_put(&ek->h, &svc_expkey_cache);
+ cache_put(&ek->h, &svc_expkey_cache);
}
svc_expkey_cache.nextcheck = get_seconds();
}
@@ -692,7 +800,7 @@ static void exp_unhash(struct svc_export *exp)
ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
if (ek && !IS_ERR(ek)) {
ek->h.expiry_time = get_seconds()-1;
- expkey_put(&ek->h, &svc_expkey_cache);
+ cache_put(&ek->h, &svc_expkey_cache);
}
svc_expkey_cache.nextcheck = get_seconds();
}
@@ -741,8 +849,8 @@ exp_export(struct nfsctl_export *nxp)
if ((nxp->ex_flags & NFSEXP_FSID) &&
(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) &&
!IS_ERR(fsid_key) &&
- fsid_key->ek_export &&
- fsid_key->ek_export != exp)
+ fsid_key->ek_mnt &&
+ (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) )
goto finish;
if (exp) {
@@ -775,13 +883,13 @@ exp_export(struct nfsctl_export *nxp)
new.ex_anon_gid = nxp->ex_anon_gid;
new.ex_fsid = nxp->ex_dev;
- exp = svc_export_lookup(&new, 1);
+ exp = svc_export_lookup(&new);
+ if (exp)
+ exp = svc_export_update(&new, exp);
- if (exp == NULL)
+ if (!exp)
goto finish;
- err = 0;
-
if (exp_hash(clp, exp) ||
exp_fsid_hash(clp, exp)) {
/* failed to create at least one index */
@@ -794,7 +902,7 @@ finish:
if (exp)
exp_put(exp);
if (fsid_key && !IS_ERR(fsid_key))
- expkey_put(&fsid_key->h, &svc_expkey_cache);
+ cache_put(&fsid_key->h, &svc_expkey_cache);
if (clp)
auth_domain_put(clp);
path_release(&nd);
@@ -912,6 +1020,24 @@ out:
return err;
}
+struct svc_export *
+exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
+ struct cache_req *reqp)
+{
+ struct svc_export *exp;
+ struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
+ if (!ek || IS_ERR(ek))
+ return ERR_PTR(PTR_ERR(ek));
+
+ exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp);
+ cache_put(&ek->h, &svc_expkey_cache);
+
+ if (!exp || IS_ERR(exp))
+ return ERR_PTR(PTR_ERR(exp));
+ return exp;
+}
+
+
/*
* Called when we need the filehandle for the root of the pseudofs,
* for a given NFSv4 client. The root is defined to be the
@@ -922,6 +1048,7 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
struct cache_req *creq)
{
struct svc_expkey *fsid_key;
+ struct svc_export *exp;
int rv;
u32 fsidv[2];
@@ -933,9 +1060,15 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
if (!fsid_key || IS_ERR(fsid_key))
return nfserr_perm;
- rv = fh_compose(fhp, fsid_key->ek_export,
- fsid_key->ek_export->ex_dentry, NULL);
- expkey_put(&fsid_key->h, &svc_expkey_cache);
+ exp = exp_get_by_name(clp, fsid_key->ek_mnt, fsid_key->ek_dentry, creq);
+ if (exp == NULL)
+ rv = nfserr_perm;
+ else if (IS_ERR(exp))
+ rv = nfserrno(PTR_ERR(exp));
+ else
+ rv = fh_compose(fhp, exp,
+ fsid_key->ek_dentry, NULL);
+ cache_put(&fsid_key->h, &svc_expkey_cache);
return rv;
}
@@ -1054,7 +1187,7 @@ static int e_show(struct seq_file *m, void *p)
cache_get(&exp->h);
if (cache_check(&svc_export_cache, &exp->h, NULL))
return 0;
- if (cache_put(&exp->h, &svc_export_cache)) BUG();
+ cache_put(&exp->h, &svc_export_cache);
return svc_export_show(m, &svc_export_cache, cp);
}
@@ -1129,7 +1262,6 @@ exp_delclient(struct nfsctl_client *ncp)
*/
if (dom) {
err = auth_unix_forget_old(dom);
- dom->h.expiry_time = get_seconds();
auth_domain_put(dom);
}
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 13369650cdf9..4b6aa60dfceb 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -76,21 +76,18 @@ struct ent {
char authname[IDMAP_NAMESZ];
};
-#define DefineSimpleCacheLookupMap(STRUCT, FUNC) \
- DefineCacheLookup(struct STRUCT, h, FUNC##_lookup, \
- (struct STRUCT *item, int set), /*no setup */, \
- & FUNC##_cache, FUNC##_hash(item), FUNC##_match(item, tmp), \
- STRUCT##_init(new, item), STRUCT##_update(tmp, item), 0)
-
/* Common entry handling */
#define ENT_HASHBITS 8
#define ENT_HASHMAX (1 << ENT_HASHBITS)
#define ENT_HASHMASK (ENT_HASHMAX - 1)
-static inline void
-ent_init(struct ent *new, struct ent *itm)
+static void
+ent_init(struct cache_head *cnew, struct cache_head *citm)
{
+ struct ent *new = container_of(cnew, struct ent, h);
+ struct ent *itm = container_of(citm, struct ent, h);
+
new->id = itm->id;
new->type = itm->type;
@@ -98,19 +95,21 @@ ent_init(struct ent *new, struct ent *itm)
strlcpy(new->authname, itm->authname, sizeof(new->name));
}
-static inline void
-ent_update(struct ent *new, struct ent *itm)
+static void
+ent_put(struct kref *ref)
{
- ent_init(new, itm);
+ struct ent *map = container_of(ref, struct ent, h.ref);
+ kfree(map);
}
-static void
-ent_put(struct cache_head *ch, struct cache_detail *cd)
+static struct cache_head *
+ent_alloc(void)
{
- if (cache_put(ch, cd)) {
- struct ent *map = container_of(ch, struct ent, h);
- kfree(map);
- }
+ struct ent *e = kmalloc(sizeof(*e), GFP_KERNEL);
+ if (e)
+ return &e->h;
+ else
+ return NULL;
}
/*
@@ -149,9 +148,12 @@ idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
(*bpp)[-1] = '\n';
}
-static inline int
-idtoname_match(struct ent *a, struct ent *b)
+static int
+idtoname_match(struct cache_head *ca, struct cache_head *cb)
{
+ struct ent *a = container_of(ca, struct ent, h);
+ struct ent *b = container_of(cb, struct ent, h);
+
return (a->id == b->id && a->type == b->type &&
strcmp(a->authname, b->authname) == 0);
}
@@ -184,7 +186,8 @@ warn_no_idmapd(struct cache_detail *detail)
static int idtoname_parse(struct cache_detail *, char *, int);
-static struct ent *idtoname_lookup(struct ent *, int);
+static struct ent *idtoname_lookup(struct ent *);
+static struct ent *idtoname_update(struct ent *, struct ent *);
static struct cache_detail idtoname_cache = {
.owner = THIS_MODULE,
@@ -196,6 +199,10 @@ static struct cache_detail idtoname_cache = {
.cache_parse = idtoname_parse,
.cache_show = idtoname_show,
.warn_no_listener = warn_no_idmapd,
+ .match = idtoname_match,
+ .init = ent_init,
+ .update = ent_init,
+ .alloc = ent_alloc,
};
int
@@ -238,6 +245,11 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
if (ent.h.expiry_time == 0)
goto out;
+ error = -ENOMEM;
+ res = idtoname_lookup(&ent);
+ if (!res)
+ goto out;
+
/* Name */
error = qword_get(&buf, buf1, PAGE_SIZE);
if (error == -EINVAL)
@@ -252,10 +264,11 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
memcpy(ent.name, buf1, sizeof(ent.name));
}
error = -ENOMEM;
- if ((res = idtoname_lookup(&ent, 1)) == NULL)
+ res = idtoname_update(&ent, res);
+ if (res == NULL)
goto out;
- ent_put(&res->h, &idtoname_cache);
+ cache_put(&res->h, &idtoname_cache);
error = 0;
out:
@@ -264,7 +277,31 @@ out:
return error;
}
-static DefineSimpleCacheLookupMap(ent, idtoname);
+
+static struct ent *
+idtoname_lookup(struct ent *item)
+{
+ struct cache_head *ch = sunrpc_cache_lookup(&idtoname_cache,
+ &item->h,
+ idtoname_hash(item));
+ if (ch)
+ return container_of(ch, struct ent, h);
+ else
+ return NULL;
+}
+
+static struct ent *
+idtoname_update(struct ent *new, struct ent *old)
+{
+ struct cache_head *ch = sunrpc_cache_update(&idtoname_cache,
+ &new->h, &old->h,
+ idtoname_hash(new));
+ if (ch)
+ return container_of(ch, struct ent, h);
+ else
+ return NULL;
+}
+
/*
* Name -> ID cache
@@ -291,9 +328,12 @@ nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
(*bpp)[-1] = '\n';
}
-static inline int
-nametoid_match(struct ent *a, struct ent *b)
+static int
+nametoid_match(struct cache_head *ca, struct cache_head *cb)
{
+ struct ent *a = container_of(ca, struct ent, h);
+ struct ent *b = container_of(cb, struct ent, h);
+
return (a->type == b->type && strcmp(a->name, b->name) == 0 &&
strcmp(a->authname, b->authname) == 0);
}
@@ -317,7 +357,8 @@ nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
return 0;
}
-static struct ent *nametoid_lookup(struct ent *, int);
+static struct ent *nametoid_lookup(struct ent *);
+static struct ent *nametoid_update(struct ent *, struct ent *);
static int nametoid_parse(struct cache_detail *, char *, int);
static struct cache_detail nametoid_cache = {
@@ -330,6 +371,10 @@ static struct cache_detail nametoid_cache = {
.cache_parse = nametoid_parse,
.cache_show = nametoid_show,
.warn_no_listener = warn_no_idmapd,
+ .match = nametoid_match,
+ .init = ent_init,
+ .update = ent_init,
+ .alloc = ent_alloc,
};
static int
@@ -379,10 +424,14 @@ nametoid_parse(struct cache_detail *cd, char *buf, int buflen)
set_bit(CACHE_NEGATIVE, &ent.h.flags);
error = -ENOMEM;
- if ((res = nametoid_lookup(&ent, 1)) == NULL)
+ res = nametoid_lookup(&ent);
+ if (res == NULL)
+ goto out;
+ res = nametoid_update(&ent, res);
+ if (res == NULL)
goto out;
- ent_put(&res->h, &nametoid_cache);
+ cache_put(&res->h, &nametoid_cache);
error = 0;
out:
kfree(buf1);
@@ -390,7 +439,30 @@ out:
return (error);
}
-static DefineSimpleCacheLookupMap(ent, nametoid);
+
+static struct ent *
+nametoid_lookup(struct ent *item)
+{
+ struct cache_head *ch = sunrpc_cache_lookup(&nametoid_cache,
+ &item->h,
+ nametoid_hash(item));
+ if (ch)
+ return container_of(ch, struct ent, h);
+ else
+ return NULL;
+}
+
+static struct ent *
+nametoid_update(struct ent *new, struct ent *old)
+{
+ struct cache_head *ch = sunrpc_cache_update(&nametoid_cache,
+ &new->h, &old->h,
+ nametoid_hash(new));
+ if (ch)
+ return container_of(ch, struct ent, h);
+ else
+ return NULL;
+}
/*
* Exported API
@@ -458,24 +530,24 @@ idmap_defer(struct cache_req *req)
}
static inline int
-do_idmap_lookup(struct ent *(*lookup_fn)(struct ent *, int), struct ent *key,
+do_idmap_lookup(struct ent *(*lookup_fn)(struct ent *), struct ent *key,
struct cache_detail *detail, struct ent **item,
struct idmap_defer_req *mdr)
{
- *item = lookup_fn(key, 0);
+ *item = lookup_fn(key);
if (!*item)
return -ENOMEM;
return cache_check(detail, &(*item)->h, &mdr->req);
}
static inline int
-do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *, int),
+do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *),
struct ent *key, struct cache_detail *detail,
struct ent **item)
{
int ret = -ENOMEM;
- *item = lookup_fn(key, 0);
+ *item = lookup_fn(key);
if (!*item)
goto out_err;
ret = -ETIMEDOUT;
@@ -488,7 +560,7 @@ do_idmap_lookup_nowait(struct ent *(*lookup_fn)(struct ent *, int),
goto out_put;
return 0;
out_put:
- ent_put(&(*item)->h, detail);
+ cache_put(&(*item)->h, detail);
out_err:
*item = NULL;
return ret;
@@ -496,7 +568,7 @@ out_err:
static int
idmap_lookup(struct svc_rqst *rqstp,
- struct ent *(*lookup_fn)(struct ent *, int), struct ent *key,
+ struct ent *(*lookup_fn)(struct ent *), struct ent *key,
struct cache_detail *detail, struct ent **item)
{
struct idmap_defer_req *mdr;
@@ -539,7 +611,7 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
if (ret)
return ret;
*id = item->id;
- ent_put(&item->h, &nametoid_cache);
+ cache_put(&item->h, &nametoid_cache);
return 0;
}
@@ -561,7 +633,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
ret = strlen(item->name);
BUG_ON(ret > IDMAP_NAMESZ);
memcpy(name, item->name, ret);
- ent_put(&item->h, &idtoname_cache);
+ cache_put(&item->h, &idtoname_cache);
return ret;
}
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index c8960aff0968..3ef017b3b5bd 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -134,7 +134,7 @@ static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size
return simple_transaction_read(file, buf, size, pos);
}
-static struct file_operations transaction_ops = {
+static const struct file_operations transaction_ops = {
.write = nfsctl_transaction_write,
.read = nfsctl_transaction_read,
.release = simple_transaction_release,
@@ -146,7 +146,7 @@ static int exports_open(struct inode *inode, struct file *file)
return seq_open(file, &nfs_exports_op);
}
-static struct file_operations exports_operations = {
+static const struct file_operations exports_operations = {
.open = exports_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 7a3e397b4ed3..3f2ec2e6d06c 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -506,7 +506,7 @@ fh_put(struct svc_fh *fhp)
nfsd_nr_put++;
}
if (exp) {
- svc_export_put(&exp->h, &svc_export_cache);
+ cache_put(&exp->h, &svc_export_cache);
fhp->fh_export = NULL;
}
return;
diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c
index 1cf955bcc526..57265d563804 100644
--- a/fs/nfsd/stats.c
+++ b/fs/nfsd/stats.c
@@ -80,7 +80,7 @@ static int nfsd_proc_open(struct inode *inode, struct file *file)
return single_open(file, nfsd_proc_show, NULL);
}
-static struct file_operations nfsd_proc_fops = {
+static const struct file_operations nfsd_proc_fops = {
.owner = THIS_MODULE,
.open = nfsd_proc_open,
.read = seq_read,
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 5320e5afaddb..31018333dc38 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -706,7 +706,7 @@ nfsd_close(struct file *filp)
* after it.
*/
static inline int nfsd_dosync(struct file *filp, struct dentry *dp,
- struct file_operations *fop)
+ const struct file_operations *fop)
{
struct inode *inode = dp->d_inode;
int (*fsync) (struct file *, struct dentry *, int);
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c
index 9d9ed3fe371d..d1e2c6f9f05e 100644
--- a/fs/ntfs/dir.c
+++ b/fs/ntfs/dir.c
@@ -1553,7 +1553,7 @@ static int ntfs_dir_fsync(struct file *filp, struct dentry *dentry,
#endif /* NTFS_RW */
-struct file_operations ntfs_dir_ops = {
+const struct file_operations ntfs_dir_ops = {
.llseek = generic_file_llseek, /* Seek inside directory. */
.read = generic_read_dir, /* Return -EISDIR. */
.readdir = ntfs_readdir, /* Read directory contents. */
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index f5d057e4acc2..c63a83e8da98 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -2294,7 +2294,7 @@ static int ntfs_file_fsync(struct file *filp, struct dentry *dentry,
#endif /* NTFS_RW */
-struct file_operations ntfs_file_ops = {
+const struct file_operations ntfs_file_ops = {
.llseek = generic_file_llseek, /* Seek inside file. */
.read = generic_file_read, /* Read from file. */
.aio_read = generic_file_aio_read, /* Async read from file. */
@@ -2337,6 +2337,6 @@ struct inode_operations ntfs_file_inode_ops = {
#endif /* NTFS_RW */
};
-struct file_operations ntfs_empty_file_ops = {};
+const struct file_operations ntfs_empty_file_ops = {};
struct inode_operations ntfs_empty_inode_ops = {};
diff --git a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h
index 166142960b53..bf7b3d7c0930 100644
--- a/fs/ntfs/ntfs.h
+++ b/fs/ntfs/ntfs.h
@@ -60,13 +60,13 @@ extern struct kmem_cache *ntfs_index_ctx_cache;
extern struct address_space_operations ntfs_aops;
extern struct address_space_operations ntfs_mst_aops;
-extern struct file_operations ntfs_file_ops;
+extern const struct file_operations ntfs_file_ops;
extern struct inode_operations ntfs_file_inode_ops;
-extern struct file_operations ntfs_dir_ops;
+extern const struct file_operations ntfs_dir_ops;
extern struct inode_operations ntfs_dir_inode_ops;
-extern struct file_operations ntfs_empty_file_ops;
+extern const struct file_operations ntfs_empty_file_ops;
extern struct inode_operations ntfs_empty_inode_ops;
extern struct export_operations ntfs_export_ops;
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 84f153aca692..64cd52860c87 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -2017,7 +2017,7 @@ out:
return ret;
}
-static struct file_operations ocfs2_dlm_debug_fops = {
+static const struct file_operations ocfs2_dlm_debug_fops = {
.open = ocfs2_dlm_debug_open,
.release = ocfs2_dlm_debug_release,
.read = seq_read,
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 4b4cbadd5838..34e903a6a46b 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1176,7 +1176,7 @@ struct inode_operations ocfs2_special_file_iops = {
.getattr = ocfs2_getattr,
};
-struct file_operations ocfs2_fops = {
+const struct file_operations ocfs2_fops = {
.read = do_sync_read,
.write = do_sync_write,
.sendfile = generic_file_sendfile,
@@ -1188,7 +1188,7 @@ struct file_operations ocfs2_fops = {
.aio_write = ocfs2_file_aio_write,
};
-struct file_operations ocfs2_dops = {
+const struct file_operations ocfs2_dops = {
.read = generic_read_dir,
.readdir = ocfs2_readdir,
.fsync = ocfs2_sync_file,
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
index a5ea33b24060..740c9e7ca599 100644
--- a/fs/ocfs2/file.h
+++ b/fs/ocfs2/file.h
@@ -26,8 +26,8 @@
#ifndef OCFS2_FILE_H
#define OCFS2_FILE_H
-extern struct file_operations ocfs2_fops;
-extern struct file_operations ocfs2_dops;
+extern const struct file_operations ocfs2_fops;
+extern const struct file_operations ocfs2_dops;
extern struct inode_operations ocfs2_file_iops;
extern struct inode_operations ocfs2_special_file_iops;
struct ocfs2_alloc_context;
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index aeb0106890e4..0f14276a2e51 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -581,17 +581,17 @@ int property_release (struct inode *inode, struct file *filp)
return 0;
}
-static struct file_operations openpromfs_prop_ops = {
+static const struct file_operations openpromfs_prop_ops = {
.read = property_read,
.write = property_write,
.release = property_release,
};
-static struct file_operations openpromfs_nodenum_ops = {
+static const struct file_operations openpromfs_nodenum_ops = {
.read = nodenum_read,
};
-static struct file_operations openprom_operations = {
+static const struct file_operations openprom_operations = {
.read = generic_read_dir,
.readdir = openpromfs_readdir,
};
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index f924f459bdb8..af0cb4b9e784 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -297,6 +297,25 @@ struct kobj_type ktype_part = {
.sysfs_ops = &part_sysfs_ops,
};
+static inline void partition_sysfs_add_subdir(struct hd_struct *p)
+{
+ struct kobject *k;
+
+ k = kobject_get(&p->kobj);
+ p->holder_dir = kobject_add_dir(k, "holders");
+ kobject_put(k);
+}
+
+static inline void disk_sysfs_add_subdirs(struct gendisk *disk)
+{
+ struct kobject *k;
+
+ k = kobject_get(&disk->kobj);
+ disk->holder_dir = kobject_add_dir(k, "holders");
+ disk->slave_dir = kobject_add_dir(k, "slaves");
+ kobject_put(k);
+}
+
void delete_partition(struct gendisk *disk, int part)
{
struct hd_struct *p = disk->part[part-1];
@@ -310,6 +329,8 @@ void delete_partition(struct gendisk *disk, int part)
p->ios[0] = p->ios[1] = 0;
p->sectors[0] = p->sectors[1] = 0;
devfs_remove("%s/part%d", disk->devfs_name, part);
+ if (p->holder_dir)
+ kobject_unregister(p->holder_dir);
kobject_unregister(&p->kobj);
}
@@ -337,6 +358,7 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
p->kobj.parent = &disk->kobj;
p->kobj.ktype = &ktype_part;
kobject_register(&p->kobj);
+ partition_sysfs_add_subdir(p);
disk->part[part-1] = p;
}
@@ -383,6 +405,7 @@ void register_disk(struct gendisk *disk)
if ((err = kobject_add(&disk->kobj)))
return;
disk_sysfs_symlinks(disk);
+ disk_sysfs_add_subdirs(disk);
kobject_uevent(&disk->kobj, KOBJ_ADD);
/* No minors to use for partitions */
@@ -483,6 +506,10 @@ void del_gendisk(struct gendisk *disk)
devfs_remove_disk(disk);
+ if (disk->holder_dir)
+ kobject_unregister(disk->holder_dir);
+ if (disk->slave_dir)
+ kobject_unregister(disk->slave_dir);
if (disk->driverfs_dev) {
char *disk_name = make_block_name(disk);
sysfs_remove_link(&disk->kobj, "device");
diff --git a/fs/pipe.c b/fs/pipe.c
index 4384c9290943..e2f4f1d9ffc2 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -568,7 +568,7 @@ pipe_rdwr_open(struct inode *inode, struct file *filp)
* The file_operations structs are not static because they
* are also used in linux/fs/fifo.c to do operations on FIFOs.
*/
-struct file_operations read_fifo_fops = {
+const struct file_operations read_fifo_fops = {
.llseek = no_llseek,
.read = pipe_read,
.readv = pipe_readv,
@@ -580,7 +580,7 @@ struct file_operations read_fifo_fops = {
.fasync = pipe_read_fasync,
};
-struct file_operations write_fifo_fops = {
+const struct file_operations write_fifo_fops = {
.llseek = no_llseek,
.read = bad_pipe_r,
.write = pipe_write,
@@ -592,7 +592,7 @@ struct file_operations write_fifo_fops = {
.fasync = pipe_write_fasync,
};
-struct file_operations rdwr_fifo_fops = {
+const struct file_operations rdwr_fifo_fops = {
.llseek = no_llseek,
.read = pipe_read,
.readv = pipe_readv,
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 47b7a20d45eb..4ba03009cf72 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -560,7 +560,7 @@ static void proc_kill_inodes(struct proc_dir_entry *de)
struct file * filp = list_entry(p, struct file, f_u.fu_list);
struct dentry * dentry = filp->f_dentry;
struct inode * inode;
- struct file_operations *fops;
+ const struct file_operations *fops;
if (dentry->d_op != &proc_dentry_operations)
continue;
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 95a1cf32b838..0502f17b860d 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -30,7 +30,7 @@ do { \
#endif
-extern void create_seq_entry(char *name, mode_t mode, struct file_operations *f);
+extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f);
extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **);
extern int proc_tid_stat(struct task_struct *, char *);
extern int proc_tgid_stat(struct task_struct *, char *);
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index adc2cd95169a..17f6e8fa1397 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -31,7 +31,7 @@ static int open_kcore(struct inode * inode, struct file * filp)
static ssize_t read_kcore(struct file *, char __user *, size_t, loff_t *);
-struct file_operations proc_kcore_operations = {
+const struct file_operations proc_kcore_operations = {
.read = read_kcore,
.open = open_kcore,
};
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c
index 10d37bf25206..ff3b90b56e9d 100644
--- a/fs/proc/kmsg.c
+++ b/fs/proc/kmsg.c
@@ -47,7 +47,7 @@ static unsigned int kmsg_poll(struct file *file, poll_table *wait)
}
-struct file_operations proc_kmsg_operations = {
+const struct file_operations proc_kmsg_operations = {
.read = kmsg_read,
.poll = kmsg_poll,
.open = kmsg_open,
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 1e9ea37d457e..ef5a3323f4b5 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -534,7 +534,7 @@ static int show_stat(struct seq_file *p, void *v)
if (wall_to_monotonic.tv_nsec)
--jif;
- for_each_cpu(i) {
+ for_each_possible_cpu(i) {
int j;
user = cputime64_add(user, kstat_cpu(i).cpustat.user);
@@ -731,7 +731,7 @@ static struct file_operations proc_sysrq_trigger_operations = {
struct proc_dir_entry *proc_root_kcore;
-void create_seq_entry(char *name, mode_t mode, struct file_operations *f)
+void create_seq_entry(char *name, mode_t mode, const struct file_operations *f)
{
struct proc_dir_entry *entry;
entry = create_proc_entry(name, mode, NULL);
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 4063fb32f78c..7efa73d44c9a 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -172,7 +172,7 @@ static int open_vmcore(struct inode *inode, struct file *filp)
return 0;
}
-struct file_operations proc_vmcore_operations = {
+const struct file_operations proc_vmcore_operations = {
.read = read_vmcore,
.open = open_vmcore,
};
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c
index 7a8f5595c26f..9031948fefd0 100644
--- a/fs/qnx4/dir.c
+++ b/fs/qnx4/dir.c
@@ -81,7 +81,7 @@ out:
return 0;
}
-struct file_operations qnx4_dir_operations =
+const struct file_operations qnx4_dir_operations =
{
.read = generic_read_dir,
.readdir = qnx4_readdir,
diff --git a/fs/qnx4/file.c b/fs/qnx4/file.c
index c33963fded9e..62af4b1348bd 100644
--- a/fs/qnx4/file.c
+++ b/fs/qnx4/file.c
@@ -19,7 +19,7 @@
* We have mostly NULL's here: the current defaults are ok for
* the qnx4 filesystem.
*/
-struct file_operations qnx4_file_operations =
+const struct file_operations qnx4_file_operations =
{
.llseek = generic_file_llseek,
.read = generic_file_read,
diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c
index 6ada2095b9ac..00a933eb820c 100644
--- a/fs/ramfs/file-mmu.c
+++ b/fs/ramfs/file-mmu.c
@@ -32,7 +32,7 @@ struct address_space_operations ramfs_aops = {
.commit_write = simple_commit_write
};
-struct file_operations ramfs_file_operations = {
+const struct file_operations ramfs_file_operations = {
.read = generic_file_read,
.write = generic_file_write,
.mmap = generic_file_mmap,
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index b1ca234068f6..f443a84b98a5 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -33,7 +33,7 @@ struct address_space_operations ramfs_aops = {
.commit_write = simple_commit_write
};
-struct file_operations ramfs_file_operations = {
+const struct file_operations ramfs_file_operations = {
.mmap = ramfs_nommu_mmap,
.get_unmapped_area = ramfs_nommu_get_unmapped_area,
.read = generic_file_read,
diff --git a/fs/ramfs/internal.h b/fs/ramfs/internal.h
index 272c8a7120b0..313237631b49 100644
--- a/fs/ramfs/internal.h
+++ b/fs/ramfs/internal.h
@@ -11,5 +11,5 @@
extern struct address_space_operations ramfs_aops;
-extern struct file_operations ramfs_file_operations;
+extern const struct file_operations ramfs_file_operations;
extern struct inode_operations ramfs_file_inode_operations;
diff --git a/fs/read_write.c b/fs/read_write.c
index 34b1bf259efd..6256ca81a718 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -19,7 +19,7 @@
#include <asm/uaccess.h>
#include <asm/unistd.h>
-struct file_operations generic_ro_fops = {
+const struct file_operations generic_ro_fops = {
.llseek = generic_file_llseek,
.read = generic_file_read,
.mmap = generic_file_readonly_mmap,
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
index d71ac6579289..973c819f8033 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -18,7 +18,7 @@ static int reiserfs_readdir(struct file *, void *, filldir_t);
static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
int datasync);
-struct file_operations reiserfs_dir_operations = {
+const struct file_operations reiserfs_dir_operations = {
.read = generic_read_dir,
.readdir = reiserfs_readdir,
.fsync = reiserfs_dir_fsync,
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index d0c1e865963e..010094d14da6 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -1566,7 +1566,7 @@ static ssize_t reiserfs_aio_write(struct kiocb *iocb, const char __user * buf,
return generic_file_aio_write(iocb, buf, count, pos);
}
-struct file_operations reiserfs_file_operations = {
+const struct file_operations reiserfs_file_operations = {
.read = generic_file_read,
.write = reiserfs_file_write,
.ioctl = reiserfs_ioctl,
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
index ef6caed9336b..731688e1cfe3 100644
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -470,7 +470,7 @@ static int r_open(struct inode *inode, struct file *file)
return ret;
}
-static struct file_operations r_file_operations = {
+static const struct file_operations r_file_operations = {
.open = r_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index c2fc424d7d5c..9b9eda7b335c 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -463,7 +463,7 @@ static struct address_space_operations romfs_aops = {
.readpage = romfs_readpage
};
-static struct file_operations romfs_dir_operations = {
+static const struct file_operations romfs_dir_operations = {
.read = generic_read_dir,
.readdir = romfs_readdir,
};
diff --git a/fs/select.c b/fs/select.c
index 1815a57d2255..b3a3a1326af6 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -29,12 +29,6 @@
#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
-struct poll_table_entry {
- struct file * filp;
- wait_queue_t wait;
- wait_queue_head_t * wait_address;
-};
-
struct poll_table_page {
struct poll_table_page * next;
struct poll_table_entry * entry;
@@ -64,13 +58,23 @@ void poll_initwait(struct poll_wqueues *pwq)
init_poll_funcptr(&pwq->pt, __pollwait);
pwq->error = 0;
pwq->table = NULL;
+ pwq->inline_index = 0;
}
EXPORT_SYMBOL(poll_initwait);
+static void free_poll_entry(struct poll_table_entry *entry)
+{
+ remove_wait_queue(entry->wait_address,&entry->wait);
+ fput(entry->filp);
+}
+
void poll_freewait(struct poll_wqueues *pwq)
{
struct poll_table_page * p = pwq->table;
+ int i;
+ for (i = 0; i < pwq->inline_index; i++)
+ free_poll_entry(pwq->inline_entries + i);
while (p) {
struct poll_table_entry * entry;
struct poll_table_page *old;
@@ -78,8 +82,7 @@ void poll_freewait(struct poll_wqueues *pwq)
entry = p->entry;
do {
entry--;
- remove_wait_queue(entry->wait_address,&entry->wait);
- fput(entry->filp);
+ free_poll_entry(entry);
} while (entry > p->entries);
old = p;
p = p->next;
@@ -89,12 +92,14 @@ void poll_freewait(struct poll_wqueues *pwq)
EXPORT_SYMBOL(poll_freewait);
-static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
- poll_table *_p)
+static struct poll_table_entry *poll_get_entry(poll_table *_p)
{
struct poll_wqueues *p = container_of(_p, struct poll_wqueues, pt);
struct poll_table_page *table = p->table;
+ if (p->inline_index < N_INLINE_POLL_ENTRIES)
+ return p->inline_entries + p->inline_index++;
+
if (!table || POLL_TABLE_FULL(table)) {
struct poll_table_page *new_table;
@@ -102,7 +107,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
if (!new_table) {
p->error = -ENOMEM;
__set_current_state(TASK_RUNNING);
- return;
+ return NULL;
}
new_table->entry = new_table->entries;
new_table->next = table;
@@ -110,16 +115,21 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
table = new_table;
}
- /* Add a new entry */
- {
- struct poll_table_entry * entry = table->entry;
- table->entry = entry+1;
- get_file(filp);
- entry->filp = filp;
- entry->wait_address = wait_address;
- init_waitqueue_entry(&entry->wait, current);
- add_wait_queue(wait_address,&entry->wait);
- }
+ return table->entry++;
+}
+
+/* Add a new entry */
+static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
+ poll_table *p)
+{
+ struct poll_table_entry *entry = poll_get_entry(p);
+ if (!entry)
+ return;
+ get_file(filp);
+ entry->filp = filp;
+ entry->wait_address = wait_address;
+ init_waitqueue_entry(&entry->wait, current);
+ add_wait_queue(wait_address,&entry->wait);
}
#define FDS_IN(fds, n) (fds->in + n)
@@ -210,7 +220,7 @@ int do_select(int n, fd_set_bits *fds, s64 *timeout)
for (i = 0; i < n; ++rinp, ++routp, ++rexp) {
unsigned long in, out, ex, all_bits, bit = 1, mask, j;
unsigned long res_in = 0, res_out = 0, res_ex = 0;
- struct file_operations *f_op = NULL;
+ const struct file_operations *f_op = NULL;
struct file *file = NULL;
in = *inp++; out = *outp++; ex = *exp++;
@@ -221,17 +231,18 @@ int do_select(int n, fd_set_bits *fds, s64 *timeout)
}
for (j = 0; j < __NFDBITS; ++j, ++i, bit <<= 1) {
+ int fput_needed;
if (i >= n)
break;
if (!(bit & all_bits))
continue;
- file = fget(i);
+ file = fget_light(i, &fput_needed);
if (file) {
f_op = file->f_op;
mask = DEFAULT_POLLMASK;
if (f_op && f_op->poll)
mask = (*f_op->poll)(file, retval ? NULL : wait);
- fput(file);
+ fput_light(file, fput_needed);
if ((mask & POLLIN_SET) && (in & bit)) {
res_in |= bit;
retval++;
@@ -284,16 +295,6 @@ int do_select(int n, fd_set_bits *fds, s64 *timeout)
return retval;
}
-static void *select_bits_alloc(int size)
-{
- return kmalloc(6 * size, GFP_KERNEL);
-}
-
-static void select_bits_free(void *bits, int size)
-{
- kfree(bits);
-}
-
/*
* We can actually return ERESTARTSYS instead of EINTR, but I'd
* like to be certain this leads to no problems. So I return
@@ -312,6 +313,8 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
char *bits;
int ret, size, max_fdset;
struct fdtable *fdt;
+ /* Allocate small arguments on the stack to save memory and be faster */
+ char stack_fds[SELECT_STACK_ALLOC];
ret = -EINVAL;
if (n < 0)
@@ -332,7 +335,10 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
*/
ret = -ENOMEM;
size = FDS_BYTES(n);
- bits = select_bits_alloc(size);
+ if (6*size < SELECT_STACK_ALLOC)
+ bits = stack_fds;
+ else
+ bits = kmalloc(6 * size, GFP_KERNEL);
if (!bits)
goto out_nofds;
fds.in = (unsigned long *) bits;
@@ -367,7 +373,8 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
ret = -EFAULT;
out:
- select_bits_free(bits, size);
+ if (bits != stack_fds)
+ kfree(bits);
out_nofds:
return ret;
}
@@ -551,14 +558,15 @@ static void do_pollfd(unsigned int num, struct pollfd * fdpage,
fdp = fdpage+i;
fd = fdp->fd;
if (fd >= 0) {
- struct file * file = fget(fd);
+ int fput_needed;
+ struct file * file = fget_light(fd, &fput_needed);
mask = POLLNVAL;
if (file != NULL) {
mask = DEFAULT_POLLMASK;
if (file->f_op && file->f_op->poll)
mask = file->f_op->poll(file, *pwait);
mask &= fdp->events | POLLERR | POLLHUP;
- fput(file);
+ fput_light(file, fput_needed);
}
if (mask) {
*pwait = NULL;
@@ -619,6 +627,9 @@ static int do_poll(unsigned int nfds, struct poll_list *list,
return count;
}
+#define N_STACK_PPS ((sizeof(stack_pps) - sizeof(struct poll_list)) / \
+ sizeof(struct pollfd))
+
int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout)
{
struct poll_wqueues table;
@@ -628,6 +639,9 @@ int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout)
struct poll_list *walk;
struct fdtable *fdt;
int max_fdset;
+ /* Allocate small arguments on the stack to save memory and be faster */
+ char stack_pps[POLL_STACK_ALLOC];
+ struct poll_list *stack_pp = NULL;
/* Do a sanity check on nfds ... */
rcu_read_lock();
@@ -645,14 +659,23 @@ int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout)
err = -ENOMEM;
while(i!=0) {
struct poll_list *pp;
- pp = kmalloc(sizeof(struct poll_list)+
- sizeof(struct pollfd)*
- (i>POLLFD_PER_PAGE?POLLFD_PER_PAGE:i),
- GFP_KERNEL);
- if(pp==NULL)
- goto out_fds;
+ int num, size;
+ if (stack_pp == NULL)
+ num = N_STACK_PPS;
+ else
+ num = POLLFD_PER_PAGE;
+ if (num > i)
+ num = i;
+ size = sizeof(struct poll_list) + sizeof(struct pollfd)*num;
+ if (!stack_pp)
+ stack_pp = pp = (struct poll_list *)stack_pps;
+ else {
+ pp = kmalloc(size, GFP_KERNEL);
+ if (!pp)
+ goto out_fds;
+ }
pp->next=NULL;
- pp->len = (i>POLLFD_PER_PAGE?POLLFD_PER_PAGE:i);
+ pp->len = num;
if (head == NULL)
head = pp;
else
@@ -660,7 +683,7 @@ int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout)
walk = pp;
if (copy_from_user(pp->entries, ufds + nfds-i,
- sizeof(struct pollfd)*pp->len)) {
+ sizeof(struct pollfd)*num)) {
err = -EFAULT;
goto out_fds;
}
@@ -689,7 +712,8 @@ out_fds:
walk = head;
while(walk!=NULL) {
struct poll_list *pp = walk->next;
- kfree(walk);
+ if (walk != stack_pp)
+ kfree(walk);
walk = pp;
}
poll_freewait(&table);
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 0424d06b147e..34c7a11d91f0 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -34,7 +34,7 @@ static int smb_rename(struct inode *, struct dentry *,
static int smb_make_node(struct inode *,struct dentry *,int,dev_t);
static int smb_link(struct dentry *, struct inode *, struct dentry *);
-struct file_operations smb_dir_operations =
+const struct file_operations smb_dir_operations =
{
.read = generic_read_dir,
.readdir = smb_readdir,
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index 7042e62726a4..c56bd99a9701 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -401,7 +401,7 @@ smb_file_permission(struct inode *inode, int mask, struct nameidata *nd)
return error;
}
-struct file_operations smb_file_operations =
+const struct file_operations smb_file_operations =
{
.llseek = remote_llseek,
.read = smb_file_read,
diff --git a/fs/smbfs/proto.h b/fs/smbfs/proto.h
index e866ec8660d0..47664597e6b1 100644
--- a/fs/smbfs/proto.h
+++ b/fs/smbfs/proto.h
@@ -35,7 +35,7 @@ extern int smb_proc_symlink(struct smb_sb_info *server, struct dentry *d, const
extern int smb_proc_link(struct smb_sb_info *server, struct dentry *dentry, struct dentry *new_dentry);
extern void smb_install_null_ops(struct smb_ops *ops);
/* dir.c */
-extern struct file_operations smb_dir_operations;
+extern const struct file_operations smb_dir_operations;
extern struct inode_operations smb_dir_inode_operations;
extern struct inode_operations smb_dir_inode_operations_unix;
extern void smb_new_dentry(struct dentry *dentry);
@@ -64,7 +64,7 @@ extern int smb_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat
extern int smb_notify_change(struct dentry *dentry, struct iattr *attr);
/* file.c */
extern struct address_space_operations smb_file_aops;
-extern struct file_operations smb_file_operations;
+extern const struct file_operations smb_file_operations;
extern struct inode_operations smb_file_inode_operations;
/* ioctl.c */
extern int smb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index 78899eeab974..c16a93c353c0 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -163,7 +163,7 @@ static int release(struct inode * inode, struct file * file)
return 0;
}
-struct file_operations bin_fops = {
+const struct file_operations bin_fops = {
.read = read,
.write = write,
.mmap = mmap,
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 9ee956864445..f26880a4785e 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -503,7 +503,7 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
return offset;
}
-struct file_operations sysfs_dir_operations = {
+const struct file_operations sysfs_dir_operations = {
.open = sysfs_dir_open,
.release = sysfs_dir_close,
.llseek = sysfs_dir_lseek,
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 5e83e7246788..830f76fa098c 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -348,7 +348,7 @@ static int sysfs_release(struct inode * inode, struct file * filp)
return 0;
}
-struct file_operations sysfs_file_operations = {
+const struct file_operations sysfs_file_operations = {
.read = sysfs_read_file,
.write = sysfs_write_file,
.llseek = generic_file_llseek,
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index cf11d5b789d9..32958a7c50e9 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -21,9 +21,9 @@ extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
extern struct rw_semaphore sysfs_rename_sem;
extern struct super_block * sysfs_sb;
-extern struct file_operations sysfs_dir_operations;
-extern struct file_operations sysfs_file_operations;
-extern struct file_operations bin_fops;
+extern const struct file_operations sysfs_dir_operations;
+extern const struct file_operations sysfs_file_operations;
+extern const struct file_operations bin_fops;
extern struct inode_operations sysfs_dir_inode_operations;
extern struct inode_operations sysfs_symlink_inode_operations;
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index cce8b05cba5a..8c66e9270dd6 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -20,7 +20,7 @@
static int sysv_readdir(struct file *, void *, filldir_t);
-struct file_operations sysv_dir_operations = {
+const struct file_operations sysv_dir_operations = {
.read = generic_read_dir,
.readdir = sysv_readdir,
.fsync = sysv_sync_file,
diff --git a/fs/sysv/file.c b/fs/sysv/file.c
index da69abc06240..a59e303135fa 100644
--- a/fs/sysv/file.c
+++ b/fs/sysv/file.c
@@ -19,7 +19,7 @@
* We have mostly NULLs here: the current defaults are OK for
* the coh filesystem.
*/
-struct file_operations sysv_file_operations = {
+const struct file_operations sysv_file_operations = {
.llseek = generic_file_llseek,
.read = generic_file_read,
.write = generic_file_write,
diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h
index b7f9b4a42aab..393a480e4deb 100644
--- a/fs/sysv/sysv.h
+++ b/fs/sysv/sysv.h
@@ -159,8 +159,8 @@ extern ino_t sysv_inode_by_name(struct dentry *);
extern struct inode_operations sysv_file_inode_operations;
extern struct inode_operations sysv_dir_inode_operations;
extern struct inode_operations sysv_fast_symlink_inode_operations;
-extern struct file_operations sysv_file_operations;
-extern struct file_operations sysv_dir_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 struct super_operations sysv_sops;
extern struct dentry_operations sysv_dentry_operations;
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index f5222527fe39..8c28efa3b8ff 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -42,7 +42,7 @@ static int do_udf_readdir(struct inode *, struct file *, filldir_t, void *);
/* readdir and lookup functions */
-struct file_operations udf_dir_operations = {
+const struct file_operations udf_dir_operations = {
.read = generic_read_dir,
.readdir = udf_readdir,
.ioctl = udf_ioctl,
diff --git a/fs/udf/file.c b/fs/udf/file.c
index a6f2acc1f15c..e34b00e303f1 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -248,7 +248,7 @@ static int udf_release_file(struct inode * inode, struct file * filp)
return 0;
}
-struct file_operations udf_file_operations = {
+const struct file_operations udf_file_operations = {
.read = generic_file_read,
.ioctl = udf_ioctl,
.open = generic_file_open,
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 1d5800e0cbe7..023e19ba5a2e 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -44,9 +44,9 @@ struct buffer_head;
struct super_block;
extern struct inode_operations udf_dir_inode_operations;
-extern struct file_operations udf_dir_operations;
+extern const struct file_operations udf_dir_operations;
extern struct inode_operations udf_file_inode_operations;
-extern struct file_operations udf_file_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;
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 7c10c68902ae..1a561202d3f4 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -620,7 +620,7 @@ int ufs_empty_dir (struct inode * inode)
return 1;
}
-struct file_operations ufs_dir_operations = {
+const struct file_operations ufs_dir_operations = {
.read = generic_read_dir,
.readdir = ufs_readdir,
.fsync = file_fsync,
diff --git a/fs/ufs/file.c b/fs/ufs/file.c
index 62ad481810ef..312fd3f86313 100644
--- a/fs/ufs/file.c
+++ b/fs/ufs/file.c
@@ -31,7 +31,7 @@
* the ufs filesystem.
*/
-struct file_operations ufs_file_operations = {
+const struct file_operations ufs_file_operations = {
.llseek = generic_file_llseek,
.read = generic_file_read,
.write = generic_file_write,
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index 185567a6a561..85997b1205f5 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -528,7 +528,7 @@ open_exec_out:
}
#endif /* HAVE_FOP_OPEN_EXEC */
-struct file_operations xfs_file_operations = {
+const struct file_operations xfs_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
@@ -550,7 +550,7 @@ struct file_operations xfs_file_operations = {
#endif
};
-struct file_operations xfs_invis_file_operations = {
+const struct file_operations xfs_invis_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
@@ -570,7 +570,7 @@ struct file_operations xfs_invis_file_operations = {
};
-struct file_operations xfs_dir_file_operations = {
+const struct file_operations xfs_dir_file_operations = {
.read = generic_read_dir,
.readdir = xfs_file_readdir,
.unlocked_ioctl = xfs_file_ioctl,
diff --git a/fs/xfs/linux-2.6/xfs_iops.h b/fs/xfs/linux-2.6/xfs_iops.h
index a8417d7af5f9..ad6173da5678 100644
--- a/fs/xfs/linux-2.6/xfs_iops.h
+++ b/fs/xfs/linux-2.6/xfs_iops.h
@@ -22,9 +22,9 @@ extern struct inode_operations xfs_inode_operations;
extern struct inode_operations xfs_dir_inode_operations;
extern struct inode_operations xfs_symlink_inode_operations;
-extern struct file_operations xfs_file_operations;
-extern struct file_operations xfs_dir_file_operations;
-extern struct file_operations xfs_invis_file_operations;
+extern const struct file_operations xfs_file_operations;
+extern const struct file_operations xfs_dir_file_operations;
+extern const struct file_operations xfs_invis_file_operations;
extern int xfs_ioctl(struct bhv_desc *, struct inode *, struct file *,
int, unsigned int, void __user *);