/*
* Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
*
* 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 program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The full GNU General Public License is included in this distribution in the
* file called LICENSE.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/sysdev.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/in.h>
#include <linux/sysfs.h>
#include <linux/ctype.h>
#include <linux/inet.h>
#include <linux/rtnetlink.h>
#include <net/net_namespace.h>
#include "bonding.h"
#define to_dev(obj) container_of(obj,struct device,kobj)
#define to_bond(cd) ((struct bonding *)(netdev_priv(to_net_dev(cd))))
/*---------------------------- Declarations -------------------------------*/
static int expected_refcount = -1;
/*--------------------------- Data Structures -----------------------------*/
/* Bonding sysfs lock. Why can't we just use the subsystem lock?
* Because kobject_register tries to acquire the subsystem lock. If
* we already hold the lock (which we would if the user was creating
* a new bond through the sysfs interface), we deadlock.
* This lock is only needed when deleting a bond - we need to make sure
* that we don't collide with an ongoing ioctl.
*/
struct rw_semaphore bonding_rwsem;
/*------------------------------ Functions --------------------------------*/
/*
* "show" function for the bond_masters attribute.
* The class parameter is ignored.
*/
static ssize_t bonding_show_bonds(struct class *cls, char *buf)
{
int res = 0;
struct bonding *bond;
down_read(&(bonding_rwsem));
list_for_each_entry(bond, &bond_dev_list, bond_list) {
if (res > (PAGE_SIZE - IFNAMSIZ)) {
/* not enough space for another interface name */
if ((PAGE_SIZE - res) > 10)
res = PAGE_SIZE - 10;
res += sprintf(buf + res, "++more++ ");
break;
}
res += sprintf(buf + res, "%s ", bond->dev->name);
}
if (res)
buf[res-1] = '\n'; /* eat the leftover space */
up_read(&(bonding_rwsem));
return res;
}
/*
* "store" function for the bond_masters attribute. This is what
* creates and deletes entire bonds.
*
* The class parameter is ignored.
*
*/
static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t count)
{
char command[IFNAMSIZ + 1] = {0, };
char *ifname;
int rv, res = count;
struct bonding *bond;
sscanf(buffer, "%16s", command); /* IFNAMSIZ*/
ifname = command + 1;
if ((strlen(command) <= 1) ||
!dev_valid_name(ifname))
goto err_no_cmd;
if (command[0] == '+') {
printk(KERN_INFO DRV_NAME
": %s is being created...\n", ifname);
rv = bond_create(ifname, &bonding_defaults);
if (rv) {
printk(KERN_INFO DRV_NAME ": Bond creation failed.\n");
res = rv;
}
goto out;
}
if (command[0] == '-') {
rtnl_lock();
down_write(&bonding_rwsem);
list_for_each_entry(bond, &bond_dev_list, bond_list)
if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) {
/* check the ref count on the bond's kobject.
* If it's > expected, then there's a file open,
* and we have to fail.
*/
if (atomic_read(&bond->dev->dev.kobj.kref.refcount)
> expected_refcount){
printk(KERN_INFO DRV_NAME
": Unable remove bond %s due to open references.\n",
ifname);
res = -EPERM;
goto out_unlock;
}
printk(KERN_INFO DRV_NAME
": %s is being deleted...\n",
bond->dev->name);
bond_destroy(bond);
goto out_unlock;
}
printk(KERN_ERR DRV_NAME
": unable to delete non-existent bond %s\n", ifname);
res = -ENODEV;
goto out_unlock;
}
err_no_cmd:
printk(KERN_ERR DRV_NAME
": no command found in bonding_masters. Use +ifname or -ifname.\n");
return -EPERM;
out_unlock:
up_write(&bonding_rwsem);
rtnl_unlock();
/* Always return either count or an error. If you return 0, you'll
* get called forever, which is bad.
*/
out:
return res;
}
/* class attribute for bond_masters file. This ends up in /sys/class/net */
static CLASS_ATTR(bonding_masters, S_IWUSR | S_IRUGO,
bonding_show_bonds, bonding_store_bonds);
int bond_create_slave_symlinks(struct net_device *master, struct net_device *slave)
{
char linkname[IFNAMSIZ+7];
int ret = 0;
/* first, create a link from the slave back to the master */
ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj),
"master");
if (ret)
return ret;
/* next, create a link from the master to the slave */
sprintf(linkname,"slave_%s",slave->name);
ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),
linkname);
return ret;
|