Revision 1ab5ecb90cb6a3df1476e052f76a6e8f6511cb3d authored by Stanislav Kinsbursky on 12 March 2012, 02:59:41 UTC, committed by David S. Miller on 13 March 2012, 00:14:00 UTC
v3: added previously removed sock_put() to the tun_release() callback, because
sk_release_kernel() doesn't drop the socket reference.

v2: sk_release_kernel() used for socket release. Dummy tun_release() is
required for sk_release_kernel() ---> sock_release() ---> sock->ops->release()
call.

TUN was designed to destroy it's socket on network namesapce shutdown. But this
will never happen for persistent device, because it's socket holds network
namespace.
This patch removes of holding network namespace by TUN socket and replaces it
by creating socket in init_net and then changing it's net it to desired one. On
shutdown socket is moved back to init_net prior to final put.

Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent de5c374
Raw File
dummy.c
/*
 * dummy.c
 *
 * Copyright 2010 Wolfson Microelectronics PLC.
 *
 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This is useful for systems with mixed controllable and
 * non-controllable regulators, as well as for allowing testing on
 * systems with no controllable regulators.
 */

#include <linux/err.h>
#include <linux/export.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>

#include "dummy.h"

struct regulator_dev *dummy_regulator_rdev;

static struct regulator_init_data dummy_initdata;

static struct regulator_ops dummy_ops;

static struct regulator_desc dummy_desc = {
	.name = "dummy",
	.id = -1,
	.type = REGULATOR_VOLTAGE,
	.owner = THIS_MODULE,
	.ops = &dummy_ops,
};

static int __devinit dummy_regulator_probe(struct platform_device *pdev)
{
	int ret;

	dummy_regulator_rdev = regulator_register(&dummy_desc, NULL,
						  &dummy_initdata, NULL, NULL);
	if (IS_ERR(dummy_regulator_rdev)) {
		ret = PTR_ERR(dummy_regulator_rdev);
		pr_err("Failed to register regulator: %d\n", ret);
		return ret;
	}

	return 0;
}

static struct platform_driver dummy_regulator_driver = {
	.probe		= dummy_regulator_probe,
	.driver		= {
		.name		= "reg-dummy",
		.owner		= THIS_MODULE,
	},
};

static struct platform_device *dummy_pdev;

void __init regulator_dummy_init(void)
{
	int ret;

	dummy_pdev = platform_device_alloc("reg-dummy", -1);
	if (!dummy_pdev) {
		pr_err("Failed to allocate dummy regulator device\n");
		return;
	}

	ret = platform_device_add(dummy_pdev);
	if (ret != 0) {
		pr_err("Failed to register dummy regulator device: %d\n", ret);
		platform_device_put(dummy_pdev);
		return;
	}

	ret = platform_driver_register(&dummy_regulator_driver);
	if (ret != 0) {
		pr_err("Failed to register dummy regulator driver: %d\n", ret);
		platform_device_unregister(dummy_pdev);
	}
}
back to top