Merge ../linux-2.6

This commit is contained in:
Paul Mackerras 2006-03-29 13:24:50 +11:00
commit bac30d1a78
779 changed files with 22983 additions and 7760 deletions

View file

@ -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);

View file

@ -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,

View file

@ -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,

View file

@ -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)
{

View file

@ -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,

View file

@ -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,

View file

@ -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;

View file

@ -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,

View file

@ -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,

View file

@ -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,
};

View file

@ -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;

View file

@ -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,
};

View file

@ -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,

View file

@ -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 */

View file

@ -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! */

View file

@ -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,

View file

@ -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 *);

View file

@ -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);
p, (int) p->d_name.len, p->d_name.name);
if (!simple_empty_nolock(dentry)) {
this_parent = dentry;
goto repeat;
}
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);
p, (int) p->d_name.len, p->d_name.name);
if (!list_empty(&dentry->d_subdirs)) {
this_parent = dentry;
goto repeat;
}
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))
if (d_mountpoint(p)) {
/* Can we umount this guy */
if (autofs4_mount_busy(mnt, p))
goto cont;
/* Can we umount this guy */
if (autofs4_check_mount(mnt, dentry))
return dentry;
/* 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;
}
if (this_parent != parent) {
next = this_parent->d_u.d_child.next;
this_parent = this_parent->d_parent;
goto resume;
}
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);
/* 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(&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;
}

View file

@ -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:

View file

@ -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);

View file

@ -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;
}

View file

@ -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,

View file

@ -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,
};

View file

@ -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 */

View file

@ -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,

View file

@ -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,

View file

@ -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,
};

View file

@ -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,

View file

@ -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);

View file

@ -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);

View file

@ -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,

View file

@ -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);

View file

@ -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,

View file

@ -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,

View file

@ -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,
};

View file

@ -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,

View file

@ -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;
}

View file

@ -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;

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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;

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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
};

View file

@ -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,

View file

@ -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;

View file

@ -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,

View file

@ -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?*/

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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;

View file

@ -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 */
};

View file

@ -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);
}

View file

@ -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);

View file

@ -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,
};

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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

View file

@ -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,

View file

@ -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 */

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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);
}

View file

@ -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,

View file

@ -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,

View file

@ -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;

View file

@ -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,

View file

@ -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,

View file

@ -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)

View file

@ -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,

View file

@ -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,

View file

@ -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;

View file

@ -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,
};

View file

@ -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,

View file

@ -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,

View file

@ -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);

View file

@ -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,

View file

@ -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 */

View file

@ -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,

View file

@ -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,

View file

@ -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.
*

View file

@ -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,

View file

@ -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,

View file

@ -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)

View file

@ -546,33 +546,6 @@ struct path {
struct dentry *dentry;
};
static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd)
{
int error;
void *cookie;
struct dentry *dentry = path->dentry;
touch_atime(path->mnt, dentry);
nd_set_link(nd, NULL);
if (path->mnt == nd->mnt)
mntget(path->mnt);
cookie = dentry->d_inode->i_op->follow_link(dentry, nd);
error = PTR_ERR(cookie);
if (!IS_ERR(cookie)) {
char *s = nd_get_link(nd);
error = 0;
if (s)
error = __vfs_follow_link(nd, s);
if (dentry->d_inode->i_op->put_link)
dentry->d_inode->i_op->put_link(dentry, nd, cookie);
}
dput(dentry);
mntput(path->mnt);
return error;
}
static inline void dput_path(struct path *path, struct nameidata *nd)
{
dput(path->dentry);
@ -589,6 +562,36 @@ static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
nd->dentry = path->dentry;
}
static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd)
{
int error;
void *cookie;
struct dentry *dentry = path->dentry;
touch_atime(path->mnt, dentry);
nd_set_link(nd, NULL);
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)) {
char *s = nd_get_link(nd);
error = 0;
if (s)
error = __vfs_follow_link(nd, s);
if (dentry->d_inode->i_op->put_link)
dentry->d_inode->i_op->put_link(dentry, nd, cookie);
}
dput(dentry);
mntput(path->mnt);
return error;
}
/*
* This limits recursive symlink follows to 8, while
* limiting consecutive symlinks to 40.

View file

@ -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;
}

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,13 +206,58 @@ 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 = {
static inline int expkey_match (struct cache_head *a, struct cache_head *b)
{
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 expkey_init(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);
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];
new->ek_fsid[1] = item->ek_fsid[1];
new->ek_fsid[2] = item->ek_fsid[2];
}
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)
{
struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL);
if (i)
return &i->h;
else
return NULL;
}
static struct cache_detail svc_expkey_cache = {
.owner = THIS_MODULE,
.hash_size = EXPKEY_HASHMAX,
.hash_table = expkey_table,
@ -229,34 +266,52 @@ struct cache_detail svc_expkey_cache = {
.cache_request = expkey_request,
.cache_parse = expkey_parse,
.cache_show = expkey_show,
.match = expkey_match,
.init = expkey_init,
.update = expkey_update,
.alloc = expkey_alloc,
};
static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b)
static struct svc_expkey *
svc_expkey_lookup(struct svc_expkey *item)
{
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)
return 0;
return 1;
struct cache_head *ch;
int hash = item->ek_fsidtype;
char * cp = (char*)item->ek_fsid;
int len = key_len(item->ek_fsidtype);
hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
hash &= EXPKEY_HASHMASK;
ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h,
hash);
if (ch)
return container_of(ch, struct svc_expkey, h);
else
return NULL;
}
static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *item)
static struct svc_expkey *
svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old)
{
cache_get(&item->ek_client->h);
new->ek_client = item->ek_client;
new->ek_fsidtype = item->ek_fsidtype;
new->ek_fsid[0] = item->ek_fsid[0];
new->ek_fsid[1] = item->ek_fsid[1];
new->ek_fsid[2] = item->ek_fsid[2];
struct cache_head *ch;
int hash = new->ek_fsidtype;
char * cp = (char*)new->ek_fsid;
int len = key_len(new->ek_fsidtype);
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;
}
static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item)
{
cache_get(&item->ek_export->h);
new->ek_export = item->ek_export;
}
static DefineSimpleCacheLookup(svc_expkey,0) /* no inplace updates */
#define EXPORT_HASHBITS 8
#define EXPORT_HASHMAX (1<< EXPORT_HASHBITS)
@ -264,25 +319,13 @@ static DefineSimpleCacheLookup(svc_expkey,0) /* no inplace updates */
static struct cache_head *export_table[EXPORT_HASHMAX];
static inline int svc_export_hash(struct svc_export *item)
static void svc_export_put(struct kref *ref)
{
int rv;
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;
}
void svc_export_put(struct cache_head *item, struct cache_detail *cd)
{
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);
}

View file

@ -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;
}

View file

@ -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,

View file

@ -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;

Some files were not shown because too many files have changed in this diff Show more