cregit-Linux how code gets into the kernel

Release 4.11 fs/autofs4/root.c

Directory: fs/autofs4
/*
 * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
 * Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org>
 * 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
 * option, any later version, incorporated herein by reference.
 */

#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/slab.h>
#include <linux/param.h>
#include <linux/time.h>
#include <linux/compat.h>
#include <linux/mutex.h>

#include "autofs_i.h"

static int autofs4_dir_symlink(struct inode *, struct dentry *, const char *);
static int autofs4_dir_unlink(struct inode *, struct dentry *);
static int autofs4_dir_rmdir(struct inode *, struct dentry *);
static int autofs4_dir_mkdir(struct inode *, struct dentry *, umode_t);
static long autofs4_root_ioctl(struct file *, unsigned int, unsigned long);
#ifdef CONFIG_COMPAT
static long autofs4_root_compat_ioctl(struct file *,
				      unsigned int, unsigned long);
#endif
static int autofs4_dir_open(struct inode *inode, struct file *file);
static struct dentry *autofs4_lookup(struct inode *,
				     struct dentry *, unsigned int);
static struct vfsmount *autofs4_d_automount(struct path *);
static int autofs4_d_manage(const struct path *, bool);
static void autofs4_dentry_release(struct dentry *);


const struct file_operations autofs4_root_operations = {
	.open		= dcache_dir_open,
	.release	= dcache_dir_close,
	.read		= generic_read_dir,
	.iterate_shared	= dcache_readdir,
	.llseek		= dcache_dir_lseek,
	.unlocked_ioctl	= autofs4_root_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl	= autofs4_root_compat_ioctl,
#endif
};


const struct file_operations autofs4_dir_operations = {
	.open		= autofs4_dir_open,
	.release	= dcache_dir_close,
	.read		= generic_read_dir,
	.iterate_shared	= dcache_readdir,
	.llseek		= dcache_dir_lseek,
};


const struct inode_operations autofs4_dir_inode_operations = {
	.lookup		= autofs4_lookup,
	.unlink		= autofs4_dir_unlink,
	.symlink	= autofs4_dir_symlink,
	.mkdir		= autofs4_dir_mkdir,
	.rmdir		= autofs4_dir_rmdir,
};


const struct dentry_operations autofs4_dentry_operations = {
	.d_automount	= autofs4_d_automount,
	.d_manage	= autofs4_d_manage,
	.d_release	= autofs4_dentry_release,
};


static void autofs4_add_active(struct dentry *dentry) { struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); struct autofs_info *ino; ino = autofs4_dentry_ino(dentry); if (ino) { spin_lock(&sbi->lookup_lock); if (!ino->active_count) { if (list_empty(&ino->active)) list_add(&ino->active, &sbi->active_list); } ino->active_count++; spin_unlock(&sbi->lookup_lock); } }

Contributors

PersonTokensPropCommitsCommitProp
Ian Kent94100.00%2100.00%
Total94100.00%2100.00%


static void autofs4_del_active(struct dentry *dentry) { struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); struct autofs_info *ino; ino = autofs4_dentry_ino(dentry); if (ino) { spin_lock(&sbi->lookup_lock); ino->active_count--; if (!ino->active_count) { if (!list_empty(&ino->active)) list_del_init(&ino->active); } spin_unlock(&sbi->lookup_lock); } }

Contributors

PersonTokensPropCommitsCommitProp
Ian Kent90100.00%2100.00%
Total90100.00%2100.00%


static int autofs4_dir_open(struct inode *inode, struct file *file) { struct dentry *dentry = file->f_path.dentry; struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); pr_debug("file=%p dentry=%p %pd\n", file, dentry, dentry); if (autofs4_oz_mode(sbi)) goto out; /* * An empty directory in an autofs file system is always a * mount point. The daemon must have failed to mount this * during lookup so it doesn't exist. This can happen, for * example, if user space returns an incorrect status for a * mount request. Otherwise we're doing a readdir on the * autofs file system so just let the libfs routines handle * it. */ spin_lock(&sbi->lookup_lock); if (!path_is_mountpoint(&file->f_path) && simple_empty(dentry)) { spin_unlock(&sbi->lookup_lock); return -ENOENT; } spin_unlock(&sbi->lookup_lock); out: return dcache_dir_open(inode, file); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton7463.25%220.00%
Ian Kent4034.19%770.00%
Josef 'Jeff' Sipek32.56%110.00%
Total117100.00%10100.00%


static void autofs4_dentry_release(struct dentry *de) { struct autofs_info *ino = autofs4_dentry_ino(de); struct autofs_sb_info *sbi = autofs4_sbi(de->d_sb); pr_debug("releasing %p\n", de); if (!ino) return; if (sbi) { spin_lock(&sbi->lookup_lock); if (!list_empty(&ino->active)) list_del(&ino->active); if (!list_empty(&ino->expiring)) list_del(&ino->expiring); spin_unlock(&sbi->lookup_lock); } autofs4_free_ino(ino); }

Contributors

PersonTokensPropCommitsCommitProp
Ian Kent7063.06%562.50%
Linus Torvalds (pre-git)2118.92%225.00%
Al Viro2018.02%112.50%
Total111100.00%8100.00%


static struct dentry *autofs4_lookup_active(struct dentry *dentry) { struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); struct dentry *parent = dentry->d_parent; const struct qstr *name = &dentry->d_name; unsigned int len = name->len; unsigned int hash = name->hash; const unsigned char *str = name->name; struct list_head *p, *head; head = &sbi->active_list; if (list_empty(head)) return NULL; spin_lock(&sbi->lookup_lock); list_for_each(p, head) { struct autofs_info *ino; struct dentry *active; const struct qstr *qstr; ino = list_entry(p, struct autofs_info, active); active = ino->dentry; spin_lock(&active->d_lock); /* Already gone? */ if ((int) d_count(active) <= 0) goto next; qstr = &active->d_name; if (active->d_name.hash != hash) goto next; if (active->d_parent != parent) goto next; if (qstr->len != len) goto next; if (memcmp(qstr->name, str, len)) goto next; if (d_unhashed(active)) { dget_dlock(active); spin_unlock(&active->d_lock); spin_unlock(&sbi->lookup_lock); return active; } next: spin_unlock(&active->d_lock); } spin_unlock(&sbi->lookup_lock); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Ian Kent25189.01%444.44%
Neil Brown165.67%111.11%
Al Viro144.96%333.33%
Nicholas Piggin10.35%111.11%
Total282100.00%9100.00%


static struct dentry *autofs4_lookup_expiring(struct dentry *dentry, bool rcu_walk) { struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); struct dentry *parent = dentry->d_parent; const struct qstr *name = &dentry->d_name; unsigned int len = name->len; unsigned int hash = name->hash; const unsigned char *str = name->name; struct list_head *p, *head; head = &sbi->expiring_list; if (list_empty(head)) return NULL; spin_lock(&sbi->lookup_lock); list_for_each(p, head) { struct autofs_info *ino; struct dentry *expiring; const struct qstr *qstr; if (rcu_walk) { spin_unlock(&sbi->lookup_lock); return ERR_PTR(-ECHILD); } ino = list_entry(p, struct autofs_info, expiring); expiring = ino->dentry; spin_lock(&expiring->d_lock); /* We've already been dentry_iput or unlinked */ if (d_really_is_negative(expiring)) goto next; qstr = &expiring->d_name; if (expiring->d_name.hash != hash) goto next; if (expiring->d_parent != parent) goto next; if (qstr->len != len) goto next; if (memcmp(qstr->name, str, len)) goto next; if (d_unhashed(expiring)) { dget_dlock(expiring); spin_unlock(&expiring->d_lock); spin_unlock(&sbi->lookup_lock); return expiring; } next: spin_unlock(&expiring->d_lock); } spin_unlock(&sbi->lookup_lock); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Ian Kent19665.12%635.29%
Neil Brown4013.29%211.76%
Linus Torvalds (pre-git)3611.96%15.88%
Al Viro123.99%211.76%
Andrew Morton113.65%317.65%
David Howells31.00%15.88%
Trond Myklebust20.66%15.88%
Nicholas Piggin10.33%15.88%
Total301100.00%17100.00%


static int autofs4_mount_wait(const struct path *path, bool rcu_walk) { struct autofs_sb_info *sbi = autofs4_sbi(path->dentry->d_sb); struct autofs_info *ino = autofs4_dentry_ino(path->dentry); int status = 0; if (ino->flags & AUTOFS_INF_PENDING) { if (rcu_walk) return -ECHILD; pr_debug("waiting for mount name=%pd\n", path->dentry); status = autofs4_wait(sbi, path, NFY_MOUNT); pr_debug("mount wait done status=%d\n", status); ino->last_used = jiffies; } return status; }

Contributors

PersonTokensPropCommitsCommitProp
Ian Kent8181.00%975.00%
Neil Brown1111.00%18.33%
Al Viro66.00%18.33%
Nicholas Piggin22.00%18.33%
Total100100.00%12100.00%


static int do_expire_wait(const struct path *path, bool rcu_walk) { struct dentry *dentry = path->dentry; struct dentry *expiring; expiring = autofs4_lookup_expiring(dentry, rcu_walk); if (IS_ERR(expiring)) return PTR_ERR(expiring); if (!expiring) return autofs4_expire_wait(path, rcu_walk); else { const struct path this = { .mnt = path->mnt, .dentry = expiring }; /* * If we are racing with expire the request might not * be quite complete, but the directory has been removed * so it must have been successful, just wait for it. */ autofs4_expire_wait(&this, 0); autofs4_del_expiring(expiring); dput(expiring); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Ian Kent7569.44%675.00%
Neil Brown2220.37%112.50%
Al Viro1110.19%112.50%
Total108100.00%8100.00%


static struct dentry *autofs4_mountpoint_changed(struct path *path) { struct dentry *dentry = path->dentry; struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); /* * If this is an indirect mount the dentry could have gone away * as a result of an expire and a new one created. */ if (autofs_type_indirect(sbi->type) && d_unhashed(dentry)) { struct dentry *parent = dentry->d_parent; struct dentry *new; new = d_lookup(parent, &dentry->d_name); if (!new) return NULL; if (new == dentry) dput(new); else { struct autofs_info *ino; ino = autofs4_dentry_ino(new); ino->last_used = jiffies; dput(path->dentry); path->dentry = new; } } return path->dentry; }

Contributors

PersonTokensPropCommitsCommitProp
Ian Kent135100.00%4100.00%
Total135100.00%4100.00%


static struct vfsmount *autofs4_d_automount(struct path *path) { struct dentry *dentry = path->dentry; struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); struct autofs_info *ino = autofs4_dentry_ino(dentry); int status; pr_debug("dentry=%p %pd\n", dentry, dentry); /* The daemon never triggers a mount. */ if (autofs4_oz_mode(sbi)) return NULL; /* * If an expire request is pending everyone must wait. * If the expire fails we're still mounted so continue * the follow and return. A return of -EAGAIN (which only * happens with indirect mounts) means the expire completed * and the directory was removed, so just go ahead and try * the mount. */ status = do_expire_wait(path, 0); if (status && status != -EAGAIN) return NULL; /* Callback to the daemon to perform the mount or wait */ spin_lock(&sbi->fs_lock); if (ino->flags & AUTOFS_INF_PENDING) { spin_unlock(&sbi->fs_lock); status = autofs4_mount_wait(path, 0); if (status) return ERR_PTR(status); goto done; } /* * If the dentry is a symlink it's equivalent to a directory * having path_is_mountpoint() true, so there's no need to call * back to the daemon. */ if (d_really_is_positive(dentry) && d_is_symlink(dentry)) { spin_unlock(&sbi->fs_lock); goto done; } if (!path_is_mountpoint(path)) { /* * It's possible that user space hasn't removed directories * after umounting a rootless multi-mount, although it * should. For v5 path_has_submounts() is sufficient to * handle this because the leaves of the directory tree under * the mount never trigger mounts themselves (they have an * autofs trigger mount mounted on them). But v4 pseudo direct * mounts do need the leaves to trigger mounts. In this case * we have no choice but to use the list_empty() check and * require user space behave. */ if (sbi->version > 4) { if (path_has_submounts(path)) { spin_unlock(&sbi->fs_lock); goto done; } } else { if (!simple_empty(dentry)) { spin_unlock(&sbi->fs_lock); goto done; } } ino->flags |= AUTOFS_INF_PENDING; spin_unlock(&sbi->fs_lock); status = autofs4_mount_wait(path, 0); spin_lock(&sbi->fs_lock); ino->flags &= ~AUTOFS_INF_PENDING; if (status) { spin_unlock(&sbi->fs_lock); return ERR_PTR(status); } } spin_unlock(&sbi->fs_lock); done: /* Mount succeeded, check if we ended up with a new dentry */ dentry = autofs4_mountpoint_changed(path); if (!dentry) return ERR_PTR(-ENOENT); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Ian Kent29491.88%1473.68%
Peter Hüwe103.12%15.26%
Neil Brown61.88%15.26%
Al Viro61.88%15.26%
David Howells41.25%210.53%
Total320100.00%19100.00%


static int autofs4_d_manage(const struct path *path, bool rcu_walk) { struct dentry *dentry = path->dentry; struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); struct autofs_info *ino = autofs4_dentry_ino(dentry); int status; pr_debug("dentry=%p %pd\n", dentry, dentry); /* The daemon never waits. */ if (autofs4_oz_mode(sbi)) { if (!path_is_mountpoint(path)) return -EISDIR; return 0; } /* Wait for pending expires */ if (do_expire_wait(path, rcu_walk) == -ECHILD) return -ECHILD; /* * This dentry may be under construction so wait on mount * completion. */ status = autofs4_mount_wait(path, rcu_walk); if (status) return status; if (rcu_walk) { /* We don't need fs_lock in rcu_walk mode, * just testing 'AUTOFS_INFO_NO_RCU' is enough. * simple_empty() takes a spinlock, so leave it * to last. * We only return -EISDIR when certain this isn't * a mount-trap. */ struct inode *inode; if (ino->flags & AUTOFS_INF_WANT_EXPIRE) return 0; if (path_is_mountpoint(path)) return 0; inode = d_inode_rcu(dentry); if (inode && S_ISLNK(inode->i_mode)) return -EISDIR; if (list_empty(&dentry->d_subdirs)) return 0; if (!simple_empty(dentry)) return -EISDIR; return 0; } spin_lock(&sbi->fs_lock); /* * If the dentry has been selected for expire while we slept * on the lock then it might go away. We'll deal with that in * ->d_automount() and wait on a new mount if the expire * succeeds or return here if it doesn't (since there's no * mount to follow with a rootless multi-mount). */ if (!(ino->flags & AUTOFS_INF_EXPIRING)) { /* * Any needed mounting has been completed and the path * updated so check if this is a rootless multi-mount so * we can avoid needless calls ->d_automount() and avoid * an incorrect ELOOP error return. */ if ((!path_is_mountpoint(path) && !simple_empty(dentry)) || (d_really_is_positive(dentry) && d_is_symlink(dentry))) status = -EISDIR; } spin_unlock(&sbi->fs_lock); return status; }

Contributors

PersonTokensPropCommitsCommitProp
Ian Kent16260.67%853.33%
Neil Brown8933.33%213.33%
David Howells145.24%320.00%
Claudiu Ghioc10.37%16.67%
Al Viro10.37%16.67%
Total267100.00%15100.00%

/* Lookups in the root directory */
static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct autofs_sb_info *sbi; struct autofs_info *ino; struct dentry *active; pr_debug("name = %pd\n", dentry); /* File name too long to exist */ if (dentry->d_name.len > NAME_MAX) return ERR_PTR(-ENAMETOOLONG); sbi = autofs4_sbi(dir->i_sb); pr_debug("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n", current->pid, task_pgrp_nr(current), sbi->catatonic, autofs4_oz_mode(sbi)); active = autofs4_lookup_active(dentry); if (active) return active; else { /* * A dentry that is not within the root can never trigger a * mount operation, unless the directory already exists, so we * can return fail immediately. The daemon however does need * to create directories within the file system. */ if (!autofs4_oz_mode(sbi) && !IS_ROOT(dentry->d_parent)) return ERR_PTR(-ENOENT); /* Mark entries in the root as mount triggers */ if (IS_ROOT(dentry->d_parent) && autofs_type_indirect(sbi->type)) __managed_dentry_set_managed(dentry); ino = autofs4_new_ino(sbi); if (!ino) return ERR_PTR(-ENOMEM); dentry->d_fsdata = ino; ino->dentry = dentry; autofs4_add_active(dentry); } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Ian Kent15679.59%1168.75%
Linus Torvalds (pre-git)178.67%16.25%
Al Viro157.65%318.75%
Andrew Morton84.08%16.25%
Total196100.00%16100.00%


static int autofs4_dir_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { 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; size_t size = strlen(symname); char *cp; pr_debug("%s <- %pd\n", symname, dentry); if (!autofs4_oz_mode(sbi)) return -EACCES; BUG_ON(!ino); autofs4_clean_ino(ino); autofs4_del_active(dentry); cp = kmalloc(size + 1, GFP_KERNEL); if (!cp) return -ENOMEM; strcpy(cp, symname); inode = autofs4_get_inode(dir->i_sb, S_IFLNK | 0555); if (!inode) { kfree(cp); return -ENOMEM; } inode->i_private = cp; inode->i_size = size; d_add(dentry, inode); dget(dentry); atomic_inc(&ino->count); p_ino = autofs4_dentry_ino(dentry->d_parent); if (p_ino && !IS_ROOT(dentry)) atomic_inc(&p_ino->count); dir->i_mtime = current_time(dir); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)12855.90%212.50%
Ian Kent5724.89%531.25%
Al Viro3414.85%637.50%
Deepa Dinamani41.75%16.25%
Rui Xiang41.75%16.25%
Andrew Morton20.87%16.25%
Total229100.00%16100.00%

/* * NOTE! * * Normal filesystems would do a "d_delete()" to tell the VFS dcache * that the file no longer exists. However, doing that means that the * VFS layer can turn the dentry into a negative dentry. We don't want * this, because the unlink is probably the result of an expire. * We simply d_drop it and add it to a expiring list in the super block, * which allows the dentry lookup to check for an incomplete expire. * * If a process is blocked on the dentry waiting for the expire to finish, * it will invalidate the dentry and try to mount with a new one. * * Also see autofs4_dir_rmdir().. */
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 -EPERM; if (atomic_dec_and_test(&ino->count)) { p_ino = autofs4_dentry_ino(dentry->d_parent); if (p_ino && !IS_ROOT(dentry)) atomic_dec(&p_ino->count); } dput(ino->dentry); d_inode(dentry)->i_size = 0; clear_nlink(d_inode(dentry)); dir->i_mtime = current_time(dir); spin_lock(&sbi->lookup_lock); __autofs4_add_expiring(dentry); d_drop(dentry); spin_unlock(&sbi->lookup_lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8350.92%19.09%
Ian Kent5835.58%436.36%
David Howells63.68%19.09%
Al Viro42.45%19.09%
Deepa Dinamani42.45%19.09%
Rui Xiang42.45%19.09%
Dave Hansen31.84%19.09%
Zhao Hongjiang10.61%19.09%
Total163100.00%11100.00%

/* * Version 4 of autofs provides a pseudo direct mount implementation * that relies on directories at the leaves of a directory tree under * an indirect mount to trigger mounts. To allow for this we need to * set the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags on the leaves * of the directory tree. There is no need to clear the automount flag * following a mount or restore it after an expire because these mounts * are always covered. However, it is necessary to ensure that these * flags are clear on non-empty directories to avoid unnecessary calls * during path walks. */
static void autofs_set_leaf_automount_flags(struct dentry *dentry) { struct dentry *parent; /* root and dentrys in the root are already handled */ if (IS_ROOT(dentry->d_parent)) return; managed_dentry_set_managed(dentry); parent = dentry->d_parent; /* only consider parents below dentrys in the root */ if (IS_ROOT(parent->d_parent)) return; managed_dentry_clear_managed(parent); }

Contributors

PersonTokensPropCommitsCommitProp
Ian Kent54100.00%1100.00%
Total54100.00%1100.00%


static void autofs_clear_leaf_automount_flags(struct dentry *dentry) { struct list_head *d_child; struct dentry *parent; /* flags for dentrys in the root are handled elsewhere */ if (IS_ROOT(dentry->d_parent)) return; managed_dentry_clear_managed(dentry); parent = dentry->d_parent; /* only consider parents below dentrys in the root */ if (IS_ROOT(parent->d_parent)) return; d_child = &dentry->d_child; /* Set parent managed if it's becoming empty */ if (d_child->next == &parent->d_subdirs && d_child->prev == &parent->d_subdirs) managed_dentry_set_managed(parent); }

Contributors

PersonTokensPropCommitsCommitProp
Ian Kent87100.00%1100.00%
Total87100.00%1100.00%


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; pr_debug("dentry %p, removing %pd\n", dentry, dentry); if (!autofs4_oz_mode(sbi)) return -EACCES; spin_lock(&sbi->lookup_lock); if (!simple_empty(dentry)) { spin_unlock(&sbi->lookup_lock); return -ENOTEMPTY; } __autofs4_add_expiring(dentry); d_drop(dentry); spin_unlock(&sbi->lookup_lock); if (sbi->version < 5) autofs_clear_leaf_automount_flags(dentry); 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); d_inode(dentry)->i_size = 0; clear_nlink(d_inode(dentry)); if (dir->i_nlink) drop_nlink(dir); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)10451.49%214.29%
Ian Kent7135.15%750.00%
Nicholas Piggin115.45%17.14%
Dave Hansen62.97%214.29%
David Howells62.97%17.14%
Al Viro41.98%17.14%
Total202100.00%14100.00%


static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, umode_t 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)) return -EACCES; pr_debug("dentry %p, creating %pd\n", dentry, dentry); BUG_ON(!ino); autofs4_clean_ino(ino); autofs4_del_active(dentry); inode = autofs4_get_inode(dir->i_sb, S_IFDIR | 0555); if (!inode) return -ENOMEM; d_add(dentry, inode); if (sbi->version < 5) autofs_set_leaf_automount_flags(dentry); dget(dentry); atomic_inc(&ino->count); p_ino = autofs4_dentry_ino(dentry->d_parent); if (p_ino && !IS_ROOT(dentry)) atomic_inc(&p_ino->count); inc_nlink(dir); dir->i_mtime = current_time(dir); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)9852.41%211.76%
Ian Kent6132.62%635.29%
Al Viro158.02%529.41%
Rui Xiang42.14%15.88%
Deepa Dinamani42.14%15.88%
Dave Hansen31.60%15.88%
Andrew Morton21.07%15.88%
Total187100.00%17100.00%

/* Get/set timeout ioctl() operation */ #ifdef CONFIG_COMPAT
static inline int autofs4_compat_get_set_timeout(struct autofs_sb_info *sbi, compat_ulong_t __user *p) { unsigned long ntimeout; int rv; rv = get_user(ntimeout, p); if (rv) goto error; rv = put_user(sbi->exp_timeout/HZ, p); if (rv) goto error; if (ntimeout > UINT_MAX/HZ) sbi->exp_timeout = 0; else sbi->exp_timeout = ntimeout * HZ; return 0; error: return rv; }

Contributors

PersonTokensPropCommitsCommitProp
Arnd Bergmann6874.73%150.00%
Ian Kent2325.27%150.00%
Total91100.00%2100.00%

#endif
static inline int autofs4_get_set_timeout(struct autofs_sb_info *sbi, unsigned long __user *p) { unsigned long ntimeout; int rv; rv = get_user(ntimeout, p); if (rv) goto error; rv = put_user(sbi->exp_timeout/HZ, p); if (rv) goto error; if (ntimeout > ULONG_MAX/HZ) sbi->exp_timeout = 0; else sbi->exp_timeout = ntimeout * HZ; return 0; error: return rv; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6873.91%133.33%
Ian Kent2325.00%133.33%
Al Viro11.09%133.33%
Total92100.00%3100.00%

/* Return protocol version */
static inline int autofs4_get_protover(struct autofs_sb_info *sbi, int __user *p) { return put_user(sbi->version, p); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2696.30%150.00%
Al Viro13.70%150.00%
Total27100.00%2100.00%

/* Return protocol sub version */
static inline int autofs4_get_protosubver(struct autofs_sb_info *sbi, int __user *p) { return put_user(sbi->sub_version, p); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton2696.30%150.00%
Al Viro13.70%150.00%
Total27100.00%2100.00%

/* * Tells the daemon whether it can umount the autofs mount. */
static inline int autofs4_ask_umount(struct vfsmount *mnt, int __user *p) { int status = 0; if (may_umount(mnt)) status = 1; pr_debug("may umount %d\n", status); status = put_user(status, p); return status; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton4994.23%240.00%
Tomohiro Kusumi11.92%120.00%
Al Viro11.92%120.00%
Ian Kent11.92%120.00%
Total52100.00%5100.00%

/* Identify autofs4_dentries - this is so we can tell if there's * an extra dentry refcount or not. We only hold a refcount on the * dentry if its non-negative (ie, d_inode != NULL) */
int is_autofs4_dentry(struct dentry *dentry) { return dentry && d_really_is_positive(dentry) && dentry->d_op == &autofs4_dentry_operations && dentry->d_fsdata != NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2890.32%150.00%
David Howells39.68%150.00%
Total31100.00%2100.00%

/* * ioctl()'s on the root directory is the chief method for the daemon to * generate kernel reactions */
static int autofs4_root_ioctl_unlocked(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { struct autofs_sb_info *sbi = autofs4_sbi(inode->i_sb); void __user *p = (void __user *)arg; pr_debug("cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n", cmd, arg, sbi, task_pgrp_nr(current)); if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) || _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT) return -ENOTTY; if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN)) return -EPERM; switch (cmd) { case AUTOFS_IOC_READY: /* Wait queue: go ahead and retry */ return autofs4_wait_release(sbi, (autofs_wqt_t) arg, 0); case AUTOFS_IOC_FAIL: /* Wait queue: fail with ENOENT */ return autofs4_wait_release(sbi, (autofs_wqt_t) arg, -ENOENT); case AUTOFS_IOC_CATATONIC: /* Enter catatonic mode (daemon shutdown) */ autofs4_catatonic_mode(sbi); return 0; case AUTOFS_IOC_PROTOVER: /* Get protocol version */ return autofs4_get_protover(sbi, p); case AUTOFS_IOC_PROTOSUBVER: /* Get protocol sub version */ return autofs4_get_protosubver(sbi, p); case AUTOFS_IOC_SETTIMEOUT: return autofs4_get_set_timeout(sbi, p); #ifdef CONFIG_COMPAT case AUTOFS_IOC_SETTIMEOUT32: return autofs4_compat_get_set_timeout(sbi, p); #endif case AUTOFS_IOC_ASKUMOUNT: return autofs4_ask_umount(filp->f_path.mnt, p); /* return a single thing to expire */ case AUTOFS_IOC_EXPIRE: return autofs4_expire_run(inode->i_sb, filp->f_path.mnt, sbi, p); /* same as above, but can send multiple expires through pipe */ case AUTOFS_IOC_EXPIRE_MULTI: return autofs4_expire_multi(inode->i_sb, filp->f_path.mnt, sbi, p); default: return -EINVAL; } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)19871.22%213.33%
Andrew Morton3211.51%533.33%
Al Viro186.47%16.67%
Arnd Bergmann165.76%16.67%
Josef 'Jeff' Sipek93.24%16.67%
Ian Kent31.08%320.00%
Frédéric Weisbecker10.36%16.67%
Pavel Emelyanov10.36%16.67%
Total278100.00%15100.00%


static long autofs4_root_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = file_inode(filp); return autofs4_root_ioctl_unlocked(inode, filp, cmd, arg); }

Contributors

PersonTokensPropCommitsCommitProp
Frédéric Weisbecker3790.24%133.33%
Al Viro37.32%133.33%
Ian Kent12.44%133.33%
Total41100.00%3100.00%

#ifdef CONFIG_COMPAT
static long autofs4_root_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = file_inode(filp); int ret; if (cmd == AUTOFS_IOC_READY || cmd == AUTOFS_IOC_FAIL) ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, arg); else ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, (unsigned long) compat_ptr(arg)); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Arnd Bergmann7696.20%150.00%
Al Viro33.80%150.00%
Total79100.00%2100.00%

#endif

Overall Contributors

PersonTokensPropCommitsCommitProp
Ian Kent213752.12%4240.38%
Linus Torvalds (pre-git)94022.93%65.77%
Andrew Morton2445.95%76.73%
Arnd Bergmann2014.90%21.92%
Al Viro2004.88%1716.35%
Neil Brown1844.49%32.88%
Frédéric Weisbecker421.02%10.96%
David Howells360.88%32.88%
Art Haas200.49%10.96%
Nicholas Piggin150.37%32.88%
Josef 'Jeff' Sipek120.29%10.96%
Dave Hansen120.29%32.88%
Deepa Dinamani120.29%10.96%
Rui Xiang120.29%10.96%
Peter Hüwe100.24%10.96%
Felipe Contreras50.12%10.96%
Tejun Heo30.07%10.96%
Arjan van de Ven30.07%21.92%
Trond Myklebust30.07%10.96%
Randy Dunlap30.07%10.96%
Dave Jones10.02%10.96%
Lucas De Marchi10.02%10.96%
Zhao Hongjiang10.02%10.96%
Pavel Emelyanov10.02%10.96%
Tomohiro Kusumi10.02%10.96%
Claudiu Ghioc10.02%10.96%
Total4100100.00%104100.00%
Directory: fs/autofs4
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.