mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
Merge ../linux-2.6
This commit is contained in:
commit
bac30d1a78
779 changed files with 22983 additions and 7760 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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! */
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 *);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
299
fs/block_dev.c
299
fs/block_dev.c
|
|
@ -266,6 +266,9 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
|
|||
mutex_init(&bdev->bd_mount_mutex);
|
||||
INIT_LIST_HEAD(&bdev->bd_inodes);
|
||||
INIT_LIST_HEAD(&bdev->bd_list);
|
||||
#ifdef CONFIG_SYSFS
|
||||
INIT_LIST_HEAD(&bdev->bd_holder_list);
|
||||
#endif
|
||||
inode_init_once(&ei->vfs_inode);
|
||||
}
|
||||
}
|
||||
|
|
@ -490,6 +493,300 @@ void bd_release(struct block_device *bdev)
|
|||
|
||||
EXPORT_SYMBOL(bd_release);
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
/*
|
||||
* Functions for bd_claim_by_kobject / bd_release_from_kobject
|
||||
*
|
||||
* If a kobject is passed to bd_claim_by_kobject()
|
||||
* and the kobject has a parent directory,
|
||||
* following symlinks are created:
|
||||
* o from the kobject to the claimed bdev
|
||||
* o from "holders" directory of the bdev to the parent of the kobject
|
||||
* bd_release_from_kobject() removes these symlinks.
|
||||
*
|
||||
* Example:
|
||||
* If /dev/dm-0 maps to /dev/sda, kobject corresponding to
|
||||
* /sys/block/dm-0/slaves is passed to bd_claim_by_kobject(), then:
|
||||
* /sys/block/dm-0/slaves/sda --> /sys/block/sda
|
||||
* /sys/block/sda/holders/dm-0 --> /sys/block/dm-0
|
||||
*/
|
||||
|
||||
static struct kobject *bdev_get_kobj(struct block_device *bdev)
|
||||
{
|
||||
if (bdev->bd_contains != bdev)
|
||||
return kobject_get(&bdev->bd_part->kobj);
|
||||
else
|
||||
return kobject_get(&bdev->bd_disk->kobj);
|
||||
}
|
||||
|
||||
static struct kobject *bdev_get_holder(struct block_device *bdev)
|
||||
{
|
||||
if (bdev->bd_contains != bdev)
|
||||
return kobject_get(bdev->bd_part->holder_dir);
|
||||
else
|
||||
return kobject_get(bdev->bd_disk->holder_dir);
|
||||
}
|
||||
|
||||
static void add_symlink(struct kobject *from, struct kobject *to)
|
||||
{
|
||||
if (!from || !to)
|
||||
return;
|
||||
sysfs_create_link(from, to, kobject_name(to));
|
||||
}
|
||||
|
||||
static void del_symlink(struct kobject *from, struct kobject *to)
|
||||
{
|
||||
if (!from || !to)
|
||||
return;
|
||||
sysfs_remove_link(from, kobject_name(to));
|
||||
}
|
||||
|
||||
/*
|
||||
* 'struct bd_holder' contains pointers to kobjects symlinked by
|
||||
* bd_claim_by_kobject.
|
||||
* It's connected to bd_holder_list which is protected by bdev->bd_sem.
|
||||
*/
|
||||
struct bd_holder {
|
||||
struct list_head list; /* chain of holders of the bdev */
|
||||
int count; /* references from the holder */
|
||||
struct kobject *sdir; /* holder object, e.g. "/block/dm-0/slaves" */
|
||||
struct kobject *hdev; /* e.g. "/block/dm-0" */
|
||||
struct kobject *hdir; /* e.g. "/block/sda/holders" */
|
||||
struct kobject *sdev; /* e.g. "/block/sda" */
|
||||
};
|
||||
|
||||
/*
|
||||
* Get references of related kobjects at once.
|
||||
* Returns 1 on success. 0 on failure.
|
||||
*
|
||||
* Should call bd_holder_release_dirs() after successful use.
|
||||
*/
|
||||
static int bd_holder_grab_dirs(struct block_device *bdev,
|
||||
struct bd_holder *bo)
|
||||
{
|
||||
if (!bdev || !bo)
|
||||
return 0;
|
||||
|
||||
bo->sdir = kobject_get(bo->sdir);
|
||||
if (!bo->sdir)
|
||||
return 0;
|
||||
|
||||
bo->hdev = kobject_get(bo->sdir->parent);
|
||||
if (!bo->hdev)
|
||||
goto fail_put_sdir;
|
||||
|
||||
bo->sdev = bdev_get_kobj(bdev);
|
||||
if (!bo->sdev)
|
||||
goto fail_put_hdev;
|
||||
|
||||
bo->hdir = bdev_get_holder(bdev);
|
||||
if (!bo->hdir)
|
||||
goto fail_put_sdev;
|
||||
|
||||
return 1;
|
||||
|
||||
fail_put_sdev:
|
||||
kobject_put(bo->sdev);
|
||||
fail_put_hdev:
|
||||
kobject_put(bo->hdev);
|
||||
fail_put_sdir:
|
||||
kobject_put(bo->sdir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Put references of related kobjects at once. */
|
||||
static void bd_holder_release_dirs(struct bd_holder *bo)
|
||||
{
|
||||
kobject_put(bo->hdir);
|
||||
kobject_put(bo->sdev);
|
||||
kobject_put(bo->hdev);
|
||||
kobject_put(bo->sdir);
|
||||
}
|
||||
|
||||
static struct bd_holder *alloc_bd_holder(struct kobject *kobj)
|
||||
{
|
||||
struct bd_holder *bo;
|
||||
|
||||
bo = kzalloc(sizeof(*bo), GFP_KERNEL);
|
||||
if (!bo)
|
||||
return NULL;
|
||||
|
||||
bo->count = 1;
|
||||
bo->sdir = kobj;
|
||||
|
||||
return bo;
|
||||
}
|
||||
|
||||
static void free_bd_holder(struct bd_holder *bo)
|
||||
{
|
||||
kfree(bo);
|
||||
}
|
||||
|
||||
/**
|
||||
* add_bd_holder - create sysfs symlinks for bd_claim() relationship
|
||||
*
|
||||
* @bdev: block device to be bd_claimed
|
||||
* @bo: preallocated and initialized by alloc_bd_holder()
|
||||
*
|
||||
* If there is no matching entry with @bo in @bdev->bd_holder_list,
|
||||
* add @bo to the list, create symlinks.
|
||||
*
|
||||
* Returns 1 if @bo was added to the list.
|
||||
* Returns 0 if @bo wasn't used by any reason and should be freed.
|
||||
*/
|
||||
static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo)
|
||||
{
|
||||
struct bd_holder *tmp;
|
||||
|
||||
if (!bo)
|
||||
return 0;
|
||||
|
||||
list_for_each_entry(tmp, &bdev->bd_holder_list, list) {
|
||||
if (tmp->sdir == bo->sdir) {
|
||||
tmp->count++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bd_holder_grab_dirs(bdev, bo))
|
||||
return 0;
|
||||
|
||||
add_symlink(bo->sdir, bo->sdev);
|
||||
add_symlink(bo->hdir, bo->hdev);
|
||||
list_add_tail(&bo->list, &bdev->bd_holder_list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* del_bd_holder - delete sysfs symlinks for bd_claim() relationship
|
||||
*
|
||||
* @bdev: block device to be bd_claimed
|
||||
* @kobj: holder's kobject
|
||||
*
|
||||
* If there is matching entry with @kobj in @bdev->bd_holder_list
|
||||
* and no other bd_claim() from the same kobject,
|
||||
* remove the struct bd_holder from the list, delete symlinks for it.
|
||||
*
|
||||
* Returns a pointer to the struct bd_holder when it's removed from the list
|
||||
* and ready to be freed.
|
||||
* Returns NULL if matching claim isn't found or there is other bd_claim()
|
||||
* by the same kobject.
|
||||
*/
|
||||
static struct bd_holder *del_bd_holder(struct block_device *bdev,
|
||||
struct kobject *kobj)
|
||||
{
|
||||
struct bd_holder *bo;
|
||||
|
||||
list_for_each_entry(bo, &bdev->bd_holder_list, list) {
|
||||
if (bo->sdir == kobj) {
|
||||
bo->count--;
|
||||
BUG_ON(bo->count < 0);
|
||||
if (!bo->count) {
|
||||
list_del(&bo->list);
|
||||
del_symlink(bo->sdir, bo->sdev);
|
||||
del_symlink(bo->hdir, bo->hdev);
|
||||
bd_holder_release_dirs(bo);
|
||||
return bo;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* bd_claim_by_kobject - bd_claim() with additional kobject signature
|
||||
*
|
||||
* @bdev: block device to be claimed
|
||||
* @holder: holder's signature
|
||||
* @kobj: holder's kobject
|
||||
*
|
||||
* Do bd_claim() and if it succeeds, create sysfs symlinks between
|
||||
* the bdev and the holder's kobject.
|
||||
* Use bd_release_from_kobject() when relesing the claimed bdev.
|
||||
*
|
||||
* Returns 0 on success. (same as bd_claim())
|
||||
* Returns errno on failure.
|
||||
*/
|
||||
static int bd_claim_by_kobject(struct block_device *bdev, void *holder,
|
||||
struct kobject *kobj)
|
||||
{
|
||||
int res;
|
||||
struct bd_holder *bo;
|
||||
|
||||
if (!kobj)
|
||||
return -EINVAL;
|
||||
|
||||
bo = alloc_bd_holder(kobj);
|
||||
if (!bo)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&bdev->bd_mutex);
|
||||
res = bd_claim(bdev, holder);
|
||||
if (res || !add_bd_holder(bdev, bo))
|
||||
free_bd_holder(bo);
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* bd_release_from_kobject - bd_release() with additional kobject signature
|
||||
*
|
||||
* @bdev: block device to be released
|
||||
* @kobj: holder's kobject
|
||||
*
|
||||
* Do bd_release() and remove sysfs symlinks created by bd_claim_by_kobject().
|
||||
*/
|
||||
static void bd_release_from_kobject(struct block_device *bdev,
|
||||
struct kobject *kobj)
|
||||
{
|
||||
struct bd_holder *bo;
|
||||
|
||||
if (!kobj)
|
||||
return;
|
||||
|
||||
mutex_lock(&bdev->bd_mutex);
|
||||
bd_release(bdev);
|
||||
if ((bo = del_bd_holder(bdev, kobj)))
|
||||
free_bd_holder(bo);
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* bd_claim_by_disk - wrapper function for bd_claim_by_kobject()
|
||||
*
|
||||
* @bdev: block device to be claimed
|
||||
* @holder: holder's signature
|
||||
* @disk: holder's gendisk
|
||||
*
|
||||
* Call bd_claim_by_kobject() with getting @disk->slave_dir.
|
||||
*/
|
||||
int bd_claim_by_disk(struct block_device *bdev, void *holder,
|
||||
struct gendisk *disk)
|
||||
{
|
||||
return bd_claim_by_kobject(bdev, holder, kobject_get(disk->slave_dir));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bd_claim_by_disk);
|
||||
|
||||
/**
|
||||
* bd_release_from_disk - wrapper function for bd_release_from_kobject()
|
||||
*
|
||||
* @bdev: block device to be claimed
|
||||
* @disk: holder's gendisk
|
||||
*
|
||||
* Call bd_release_from_kobject() and put @disk->slave_dir.
|
||||
*/
|
||||
void bd_release_from_disk(struct block_device *bdev, struct gendisk *disk)
|
||||
{
|
||||
bd_release_from_kobject(bdev, disk->slave_dir);
|
||||
kobject_put(disk->slave_dir);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bd_release_from_disk);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Tries to open block device by device number. Use it ONLY if you
|
||||
* really do not have anything better - i.e. when you are behind a
|
||||
|
|
@ -790,7 +1087,7 @@ struct address_space_operations def_blk_aops = {
|
|||
.direct_IO = blkdev_direct_IO,
|
||||
};
|
||||
|
||||
struct file_operations def_blk_fops = {
|
||||
const struct file_operations def_blk_fops = {
|
||||
.open = blkdev_open,
|
||||
.release = blkdev_close,
|
||||
.llseek = block_llseek,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
13
fs/compat.c
13
fs/compat.c
|
|
@ -1639,15 +1639,6 @@ void compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
|
|||
* This is a virtual copy of sys_select from fs/select.c and probably
|
||||
* should be compared to it from time to time
|
||||
*/
|
||||
static void *select_bits_alloc(int size)
|
||||
{
|
||||
return kmalloc(6 * size, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void select_bits_free(void *bits, int size)
|
||||
{
|
||||
kfree(bits);
|
||||
}
|
||||
|
||||
/*
|
||||
* We can actually return ERESTARTSYS instead of EINTR, but I'd
|
||||
|
|
@ -1686,7 +1677,7 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp,
|
|||
*/
|
||||
ret = -ENOMEM;
|
||||
size = FDS_BYTES(n);
|
||||
bits = select_bits_alloc(size);
|
||||
bits = kmalloc(6 * size, GFP_KERNEL);
|
||||
if (!bits)
|
||||
goto out_nofds;
|
||||
fds.in = (unsigned long *) bits;
|
||||
|
|
@ -1720,7 +1711,7 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp,
|
|||
compat_set_fd_set(n, exp, fds.res_ex);
|
||||
|
||||
out:
|
||||
select_bits_free(bits, size);
|
||||
kfree(bits);
|
||||
out_nofds:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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?*/
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
57
fs/namei.c
57
fs/namei.c
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
370
fs/nfsd/export.c
370
fs/nfsd/export.c
|
|
@ -57,27 +57,17 @@ static int exp_verify_string(char *cp, int max);
|
|||
#define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1)
|
||||
static struct cache_head *expkey_table[EXPKEY_HASHMAX];
|
||||
|
||||
static inline int svc_expkey_hash(struct svc_expkey *item)
|
||||
static void expkey_put(struct kref *ref)
|
||||
{
|
||||
int hash = item->ek_fsidtype;
|
||||
char * cp = (char*)item->ek_fsid;
|
||||
int len = key_len(item->ek_fsidtype);
|
||||
struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
|
||||
|
||||
hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
|
||||
hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
|
||||
return hash & EXPKEY_HASHMASK;
|
||||
}
|
||||
|
||||
void expkey_put(struct cache_head *item, struct cache_detail *cd)
|
||||
{
|
||||
if (cache_put(item, cd)) {
|
||||
struct svc_expkey *key = container_of(item, struct svc_expkey, h);
|
||||
if (test_bit(CACHE_VALID, &item->flags) &&
|
||||
!test_bit(CACHE_NEGATIVE, &item->flags))
|
||||
exp_put(key->ek_export);
|
||||
auth_domain_put(key->ek_client);
|
||||
kfree(key);
|
||||
if (test_bit(CACHE_VALID, &key->h.flags) &&
|
||||
!test_bit(CACHE_NEGATIVE, &key->h.flags)) {
|
||||
dput(key->ek_dentry);
|
||||
mntput(key->ek_mnt);
|
||||
}
|
||||
auth_domain_put(key->ek_client);
|
||||
kfree(key);
|
||||
}
|
||||
|
||||
static void expkey_request(struct cache_detail *cd,
|
||||
|
|
@ -95,7 +85,10 @@ static void expkey_request(struct cache_detail *cd,
|
|||
(*bpp)[-1] = '\n';
|
||||
}
|
||||
|
||||
static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *, int);
|
||||
static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old);
|
||||
static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *);
|
||||
static struct cache_detail svc_expkey_cache;
|
||||
|
||||
static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
|
||||
{
|
||||
/* client fsidtype fsid [path] */
|
||||
|
|
@ -106,6 +99,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
|
|||
int fsidtype;
|
||||
char *ep;
|
||||
struct svc_expkey key;
|
||||
struct svc_expkey *ek;
|
||||
|
||||
if (mesg[mlen-1] != '\n')
|
||||
return -EINVAL;
|
||||
|
|
@ -150,40 +144,38 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
|
|||
key.ek_fsidtype = fsidtype;
|
||||
memcpy(key.ek_fsid, buf, len);
|
||||
|
||||
ek = svc_expkey_lookup(&key);
|
||||
err = -ENOMEM;
|
||||
if (!ek)
|
||||
goto out;
|
||||
|
||||
/* now we want a pathname, or empty meaning NEGATIVE */
|
||||
err = -EINVAL;
|
||||
if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0)
|
||||
goto out;
|
||||
dprintk("Path seems to be <%s>\n", buf);
|
||||
err = 0;
|
||||
if (len == 0) {
|
||||
struct svc_expkey *ek;
|
||||
set_bit(CACHE_NEGATIVE, &key.h.flags);
|
||||
ek = svc_expkey_lookup(&key, 1);
|
||||
ek = svc_expkey_update(&key, ek);
|
||||
if (ek)
|
||||
expkey_put(&ek->h, &svc_expkey_cache);
|
||||
cache_put(&ek->h, &svc_expkey_cache);
|
||||
else err = -ENOMEM;
|
||||
} else {
|
||||
struct nameidata nd;
|
||||
struct svc_expkey *ek;
|
||||
struct svc_export *exp;
|
||||
err = path_lookup(buf, 0, &nd);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
dprintk("Found the path %s\n", buf);
|
||||
exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
|
||||
|
||||
err = -ENOENT;
|
||||
if (!exp)
|
||||
goto out_nd;
|
||||
key.ek_export = exp;
|
||||
dprintk("And found export\n");
|
||||
key.ek_mnt = nd.mnt;
|
||||
key.ek_dentry = nd.dentry;
|
||||
|
||||
ek = svc_expkey_lookup(&key, 1);
|
||||
ek = svc_expkey_update(&key, ek);
|
||||
if (ek)
|
||||
expkey_put(&ek->h, &svc_expkey_cache);
|
||||
exp_put(exp);
|
||||
err = 0;
|
||||
out_nd:
|
||||
cache_put(&ek->h, &svc_expkey_cache);
|
||||
else
|
||||
err = -ENOMEM;
|
||||
path_release(&nd);
|
||||
}
|
||||
cache_flush();
|
||||
|
|
@ -214,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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in a new issue