1
0
Files
kernel-49/fs/autofs4/inode.c
Greg Kroah-Hartman cf697f6deb Merge 4.9.163 into android-4.9
Changes in 4.9.163
	USB: serial: option: add Telit ME910 ECM composition
	USB: serial: cp210x: add ID for Ingenico 3070
	USB: serial: ftdi_sio: add ID for Hjelmslund Electronics USB485
	cpufreq: Use struct kobj_attribute instead of struct global_attr
	ncpfs: fix build warning of strncpy
	isdn: isdn_tty: fix build warning of strncpy
	staging: comedi: ni_660x: fix missing break in switch statement
	staging: wilc1000: fix to set correct value for 'vif_num'
	staging: android: ion: fix sys heap pool's gfp_flags
	ip6mr: Do not call __IP6_INC_STATS() from preemptible context
	net-sysfs: Fix mem leak in netdev_register_kobject
	sky2: Disable MSI on Dell Inspiron 1545 and Gateway P-79
	team: Free BPF filter when unregistering netdev
	bnxt_en: Drop oversize TX packets to prevent errors.
	hv_netvsc: Fix IP header checksum for coalesced packets
	net: dsa: mv88e6xxx: Fix u64 statistics
	netlabel: fix out-of-bounds memory accesses
	net: netem: fix skb length BUG_ON in __skb_to_sgvec
	net: nfc: Fix NULL dereference on nfc_llcp_build_tlv fails
	net: sit: fix memory leak in sit_init_net()
	xen-netback: don't populate the hash cache on XenBus disconnect
	xen-netback: fix occasional leak of grant ref mappings under memory pressure
	net: Add __icmp_send helper.
	net: avoid use IPCB in cipso_v4_error
	tun: fix blocking read
	tun: remove unnecessary memory barrier
	net: phy: Micrel KSZ8061: link failure after cable connect
	x86/CPU/AMD: Set the CPB bit unconditionally on F17h
	applicom: Fix potential Spectre v1 vulnerabilities
	MIPS: irq: Allocate accurate order pages for irq stack
	hugetlbfs: fix races and page leaks during migration
	exec: Fix mem leak in kernel_read_file
	media: uvcvideo: Fix 'type' check leading to overflow
	vti4: Fix a ipip packet processing bug in 'IPCOMP' virtual tunnel
	perf core: Fix perf_proc_update_handler() bug
	perf tools: Handle TOPOLOGY headers with no CPU
	IB/{hfi1, qib}: Fix WC.byte_len calculation for UD_SEND_WITH_IMM
	iommu/amd: Call free_iova_fast with pfn in map_sg
	iommu/amd: Unmap all mapped pages in error path of map_sg
	ipvs: Fix signed integer overflow when setsockopt timeout
	iommu/amd: Fix IOMMU page flush when detach device from a domain
	xtensa: SMP: fix ccount_timer_shutdown
	xtensa: SMP: fix secondary CPU initialization
	xtensa: smp_lx200_defconfig: fix vectors clash
	xtensa: SMP: mark each possible CPU as present
	xtensa: SMP: limit number of possible CPUs by NR_CPUS
	net: altera_tse: fix msgdma_tx_completion on non-zero fill_level case
	net: hns: Fix for missing of_node_put() after of_parse_phandle()
	net: hns: Fix wrong read accesses via Clause 45 MDIO protocol
	net: stmmac: dwmac-rk: fix error handling in rk_gmac_powerup()
	gpio: vf610: Mask all GPIO interrupts
	nfs: Fix NULL pointer dereference of dev_name
	qed: Fix VF probe failure while FLR
	scsi: libfc: free skb when receiving invalid flogi resp
	platform/x86: Fix unmet dependency warning for SAMSUNG_Q10
	cifs: fix computation for MAX_SMB2_HDR_SIZE
	arm64: kprobe: Always blacklist the KVM world-switch code
	x86/kexec: Don't setup EFI info if EFI runtime is not enabled
	x86_64: increase stack size for KASAN_EXTRA
	mm, memory_hotplug: is_mem_section_removable do not pass the end of a zone
	mm, memory_hotplug: test_pages_in_a_zone do not pass the end of zone
	fs/drop_caches.c: avoid softlockups in drop_pagecache_sb()
	autofs: drop dentry reference only when it is never used
	autofs: fix error return in autofs_fill_super()
	soc: fsl: qbman: avoid race in clearing QMan interrupt
	ARM: pxa: ssp: unneeded to free devm_ allocated data
	arm64: dts: add msm8996 compatible to gicv3
	usb: phy: fix link errors
	irqchip/mmp: Only touch the PJ4 IRQ & FIQ bits on enable/disable
	drm/sun4i: tcon: Prepare and enable TCON channel 0 clock at init
	dmaengine: at_xdmac: Fix wrongfull report of a channel as in use
	vsock/virtio: fix kernel panic after device hot-unplug
	vsock/virtio: reset connected sockets on device removal
	dmaengine: dmatest: Abort test in case of mapping error
	selftests: netfilter: fix config fragment CONFIG_NF_TABLES_INET
	selftests: netfilter: add simple masq/redirect test cases
	netfilter: nf_nat: skip nat clash resolution for same-origin entries
	s390/qeth: fix use-after-free in error path
	perf symbols: Filter out hidden symbols from labels
	MIPS: Remove function size check in get_frame_info()
	fs: ratelimit __find_get_block_slow() failure message.
	Input: wacom_serial4 - add support for Wacom ArtPad II tablet
	Input: elan_i2c - add id for touchpad found in Lenovo s21e-20
	iscsi_ibft: Fix missing break in switch statement
	scsi: aacraid: Fix missing break in switch statement
	futex,rt_mutex: Restructure rt_mutex_finish_proxy_lock()
	ARM: dts: exynos: Fix pinctrl definition for eMMC RTSN line on Odroid X2/U3
	ARM: dts: exynos: Add minimal clkout parameters to Exynos3250 PMU
	drm: disable uncached DMA optimization for ARM and arm64
	ARM: 8781/1: Fix Thumb-2 syscall return for binutils 2.29+
	ARM: dts: exynos: Do not ignore real-world fuse values for thermal zone 0 on Exynos5420
	perf/x86/intel: Make cpuc allocations consistent
	perf/x86/intel: Generalize dynamic constraint creation
	x86: Add TSX Force Abort CPUID/MSR
	Linux 4.9.163

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
2019-03-14 20:02:42 +07:00

377 lines
8.5 KiB
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
* option, any later version, incorporated herein by reference.
*/
#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>
#include "autofs_i.h"
#include <linux/module.h>
struct autofs_info *autofs4_new_ino(struct autofs_sb_info *sbi)
{
struct autofs_info *ino;
ino = kzalloc(sizeof(*ino), GFP_KERNEL);
if (ino) {
INIT_LIST_HEAD(&ino->active);
INIT_LIST_HEAD(&ino->expiring);
ino->last_used = jiffies;
ino->sbi = sbi;
}
return ino;
}
void autofs4_clean_ino(struct autofs_info *ino)
{
ino->uid = GLOBAL_ROOT_UID;
ino->gid = GLOBAL_ROOT_GID;
ino->last_used = jiffies;
}
void autofs4_free_ino(struct autofs_info *ino)
{
kfree(ino);
}
void autofs4_kill_sb(struct super_block *sb)
{
struct autofs_sb_info *sbi = autofs4_sbi(sb);
/*
* In the event of a failure in get_sb_nodev the superblock
* info is not present so nothing else has been setup, so
* just call kill_anon_super when we are called from
* deactivate_super.
*/
if (sbi) {
/* Free wait queues, close pipe */
autofs4_catatonic_mode(sbi);
put_pid(sbi->oz_pgrp);
}
pr_debug("shutting down\n");
kill_litter_super(sb);
if (sbi)
kfree_rcu(sbi, rcu);
}
static int autofs4_show_options(struct seq_file *m, struct dentry *root)
{
struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb);
struct inode *root_inode = d_inode(root->d_sb->s_root);
if (!sbi)
return 0;
seq_printf(m, ",fd=%d", sbi->pipefd);
if (!uid_eq(root_inode->i_uid, GLOBAL_ROOT_UID))
seq_printf(m, ",uid=%u",
from_kuid_munged(&init_user_ns, root_inode->i_uid));
if (!gid_eq(root_inode->i_gid, GLOBAL_ROOT_GID))
seq_printf(m, ",gid=%u",
from_kgid_munged(&init_user_ns, root_inode->i_gid));
seq_printf(m, ",pgrp=%d", pid_vnr(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 (autofs_type_offset(sbi->type))
seq_printf(m, ",offset");
else if (autofs_type_direct(sbi->type))
seq_printf(m, ",direct");
else
seq_printf(m, ",indirect");
#ifdef CONFIG_CHECKPOINT_RESTORE
if (sbi->pipe)
seq_printf(m, ",pipe_ino=%ld", sbi->pipe->f_inode->i_ino);
else
seq_printf(m, ",pipe_ino=-1");
#endif
return 0;
}
static void autofs4_evict_inode(struct inode *inode)
{
clear_inode(inode);
kfree(inode->i_private);
}
static const struct super_operations autofs4_sops = {
.statfs = simple_statfs,
.show_options = autofs4_show_options,
.evict_inode = autofs4_evict_inode,
};
enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto,
Opt_indirect, Opt_direct, Opt_offset};
static const match_table_t tokens = {
{Opt_fd, "fd=%u"},
{Opt_uid, "uid=%u"},
{Opt_gid, "gid=%u"},
{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, kuid_t *uid, kgid_t *gid,
int *pgrp, bool *pgrp_set, unsigned int *type,
int *minproto, int *maxproto)
{
char *p;
substring_t args[MAX_OPT_ARGS];
int option;
*uid = current_uid();
*gid = current_gid();
*minproto = AUTOFS_MIN_PROTO_VERSION;
*maxproto = AUTOFS_MAX_PROTO_VERSION;
*pipefd = -1;
if (!options)
return 1;
while ((p = strsep(&options, ",")) != NULL) {
int token;
if (!*p)
continue;
token = match_token(p, tokens, args);
switch (token) {
case Opt_fd:
if (match_int(args, pipefd))
return 1;
break;
case Opt_uid:
if (match_int(args, &option))
return 1;
*uid = make_kuid(current_user_ns(), option);
if (!uid_valid(*uid))
return 1;
break;
case Opt_gid:
if (match_int(args, &option))
return 1;
*gid = make_kgid(current_user_ns(), option);
if (!gid_valid(*gid))
return 1;
break;
case Opt_pgrp:
if (match_int(args, &option))
return 1;
*pgrp = option;
*pgrp_set = true;
break;
case Opt_minproto:
if (match_int(args, &option))
return 1;
*minproto = option;
break;
case Opt_maxproto:
if (match_int(args, &option))
return 1;
*maxproto = option;
break;
case Opt_indirect:
set_autofs_type_indirect(type);
break;
case Opt_direct:
set_autofs_type_direct(type);
break;
case Opt_offset:
set_autofs_type_offset(type);
break;
default:
return 1;
}
}
return (*pipefd < 0);
}
int autofs4_fill_super(struct super_block *s, void *data, int silent)
{
struct inode *root_inode;
struct dentry *root;
struct file *pipe;
int pipefd;
struct autofs_sb_info *sbi;
struct autofs_info *ino;
int pgrp = 0;
bool pgrp_set = false;
int ret = -EINVAL;
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
pr_debug("starting up, sbi = %p\n", sbi);
s->s_fs_info = sbi;
sbi->magic = AUTOFS_SBI_MAGIC;
sbi->pipefd = -1;
sbi->pipe = NULL;
sbi->catatonic = 1;
sbi->exp_timeout = 0;
sbi->oz_pgrp = NULL;
sbi->sb = s;
sbi->version = 0;
sbi->sub_version = 0;
set_autofs_type_indirect(&sbi->type);
sbi->min_proto = 0;
sbi->max_proto = 0;
mutex_init(&sbi->wq_mutex);
mutex_init(&sbi->pipe_mutex);
spin_lock_init(&sbi->fs_lock);
sbi->queues = NULL;
spin_lock_init(&sbi->lookup_lock);
INIT_LIST_HEAD(&sbi->active_list);
INIT_LIST_HEAD(&sbi->expiring_list);
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
s->s_magic = AUTOFS_SUPER_MAGIC;
s->s_op = &autofs4_sops;
s->s_d_op = &autofs4_dentry_operations;
s->s_time_gran = 1;
/*
* Get the root inode and dentry, but defer checking for errors.
*/
ino = autofs4_new_ino(sbi);
if (!ino) {
ret = -ENOMEM;
goto fail_free;
}
root_inode = autofs4_get_inode(s, S_IFDIR | 0755);
root = d_make_root(root_inode);
if (!root) {
ret = -ENOMEM;
goto fail_ino;
}
pipe = NULL;
root->d_fsdata = ino;
/* Can this call block? */
if (parse_options(data, &pipefd, &root_inode->i_uid, &root_inode->i_gid,
&pgrp, &pgrp_set, &sbi->type, &sbi->min_proto,
&sbi->max_proto)) {
pr_err("called with bogus options\n");
goto fail_dput;
}
/* Test versions first */
if (sbi->max_proto < AUTOFS_MIN_PROTO_VERSION ||
sbi->min_proto > AUTOFS_MAX_PROTO_VERSION) {
pr_err("kernel does not match daemon version "
"daemon (%d, %d) kernel (%d, %d)\n",
sbi->min_proto, sbi->max_proto,
AUTOFS_MIN_PROTO_VERSION, AUTOFS_MAX_PROTO_VERSION);
goto fail_dput;
}
/* 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;
if (pgrp_set) {
sbi->oz_pgrp = find_get_pid(pgrp);
if (!sbi->oz_pgrp) {
pr_err("could not find process group %d\n",
pgrp);
goto fail_dput;
}
} else {
sbi->oz_pgrp = get_task_pid(current, PIDTYPE_PGID);
}
if (autofs_type_trigger(sbi->type))
__managed_dentry_set_managed(root);
root_inode->i_fop = &autofs4_root_operations;
root_inode->i_op = &autofs4_dir_inode_operations;
pr_debug("pipe fd = %d, pgrp = %u\n", pipefd, pid_nr(sbi->oz_pgrp));
pipe = fget(pipefd);
if (!pipe) {
pr_err("could not open pipe file descriptor\n");
goto fail_put_pid;
}
ret = autofs_prepare_pipe(pipe);
if (ret < 0)
goto fail_fput;
sbi->pipe = pipe;
sbi->pipefd = pipefd;
sbi->catatonic = 0;
/*
* Success! Install the root dentry now to indicate completion.
*/
s->s_root = root;
return 0;
/*
* Failure ... clean up.
*/
fail_fput:
pr_err("pipe file descriptor does not contain proper ops\n");
fput(pipe);
fail_put_pid:
put_pid(sbi->oz_pgrp);
fail_dput:
dput(root);
goto fail_free;
fail_ino:
autofs4_free_ino(ino);
fail_free:
kfree(sbi);
s->s_fs_info = NULL;
return ret;
}
struct inode *autofs4_get_inode(struct super_block *sb, umode_t mode)
{
struct inode *inode = new_inode(sb);
if (inode == NULL)
return NULL;
inode->i_mode = mode;
if (sb->s_root) {
inode->i_uid = d_inode(sb->s_root)->i_uid;
inode->i_gid = d_inode(sb->s_root)->i_gid;
}
inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
inode->i_ino = get_next_ino();
if (S_ISDIR(mode)) {
set_nlink(inode, 2);
inode->i_op = &autofs4_dir_inode_operations;
inode->i_fop = &autofs4_dir_operations;
} else if (S_ISLNK(mode)) {
inode->i_op = &autofs4_symlink_inode_operations;
} else
WARN_ON(1);
return inode;
}