mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-14 15:54:15 +08:00
[PATCH] s390: netiucv driver fixes
[PATCH 2/9] s390: netiucv driver fixes From: Frank Pavlic <fpavlic@de.ibm.com> - missing lock initialization added - avoid duplicate iucv-interfaces to the same peer - rw-lock added for manipulating the list of defined iucv connections Signed-off-by: Frank Pavlic <fpavlic@de.ibm.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
parent
4c7ae6ea59
commit
16a83b3077
@ -112,7 +112,12 @@ struct iucv_connection {
|
|||||||
/**
|
/**
|
||||||
* Linked list of all connection structs.
|
* Linked list of all connection structs.
|
||||||
*/
|
*/
|
||||||
static struct iucv_connection *iucv_connections;
|
struct iucv_connection_struct {
|
||||||
|
struct iucv_connection *iucv_connections;
|
||||||
|
rwlock_t iucv_rwlock;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct iucv_connection_struct iucv_conns;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of event-data for the
|
* Representation of event-data for the
|
||||||
@ -1368,8 +1373,10 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf,
|
|||||||
struct net_device *ndev = priv->conn->netdev;
|
struct net_device *ndev = priv->conn->netdev;
|
||||||
char *p;
|
char *p;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
char username[10];
|
char username[9];
|
||||||
int i;
|
int i;
|
||||||
|
struct iucv_connection **clist = &iucv_conns.iucv_connections;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
|
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
|
||||||
if (count>9) {
|
if (count>9) {
|
||||||
@ -1382,7 +1389,7 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf,
|
|||||||
tmp = strsep((char **) &buf, "\n");
|
tmp = strsep((char **) &buf, "\n");
|
||||||
for (i=0, p=tmp; i<8 && *p; i++, p++) {
|
for (i=0, p=tmp; i<8 && *p; i++, p++) {
|
||||||
if (isalnum(*p) || (*p == '$'))
|
if (isalnum(*p) || (*p == '$'))
|
||||||
username[i]= *p;
|
username[i]= toupper(*p);
|
||||||
else if (*p == '\n') {
|
else if (*p == '\n') {
|
||||||
/* trailing lf, grr */
|
/* trailing lf, grr */
|
||||||
break;
|
break;
|
||||||
@ -1395,11 +1402,11 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (i<9)
|
while (i<8)
|
||||||
username[i++] = ' ';
|
username[i++] = ' ';
|
||||||
username[9] = '\0';
|
username[8] = '\0';
|
||||||
|
|
||||||
if (memcmp(username, priv->conn->userid, 8)) {
|
if (memcmp(username, priv->conn->userid, 9)) {
|
||||||
/* username changed */
|
/* username changed */
|
||||||
if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
|
if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
|
||||||
PRINT_WARN(
|
PRINT_WARN(
|
||||||
@ -1410,6 +1417,19 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf,
|
|||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
|
||||||
|
while (*clist) {
|
||||||
|
if (!strncmp(username, (*clist)->userid, 9) ||
|
||||||
|
((*clist)->netdev != ndev))
|
||||||
|
break;
|
||||||
|
clist = &((*clist)->next);
|
||||||
|
}
|
||||||
|
read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
|
||||||
|
if (*clist) {
|
||||||
|
PRINT_WARN("netiucv: Connection to %s already exists\n",
|
||||||
|
username);
|
||||||
|
return -EEXIST;
|
||||||
|
}
|
||||||
memcpy(priv->conn->userid, username, 9);
|
memcpy(priv->conn->userid, username, 9);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
@ -1781,13 +1801,15 @@ netiucv_unregister_device(struct device *dev)
|
|||||||
static struct iucv_connection *
|
static struct iucv_connection *
|
||||||
netiucv_new_connection(struct net_device *dev, char *username)
|
netiucv_new_connection(struct net_device *dev, char *username)
|
||||||
{
|
{
|
||||||
struct iucv_connection **clist = &iucv_connections;
|
unsigned long flags;
|
||||||
|
struct iucv_connection **clist = &iucv_conns.iucv_connections;
|
||||||
struct iucv_connection *conn =
|
struct iucv_connection *conn =
|
||||||
kzalloc(sizeof(struct iucv_connection), GFP_KERNEL);
|
kzalloc(sizeof(struct iucv_connection), GFP_KERNEL);
|
||||||
|
|
||||||
if (conn) {
|
if (conn) {
|
||||||
skb_queue_head_init(&conn->collect_queue);
|
skb_queue_head_init(&conn->collect_queue);
|
||||||
skb_queue_head_init(&conn->commit_queue);
|
skb_queue_head_init(&conn->commit_queue);
|
||||||
|
spin_lock_init(&conn->collect_lock);
|
||||||
conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;
|
conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;
|
||||||
conn->netdev = dev;
|
conn->netdev = dev;
|
||||||
|
|
||||||
@ -1822,8 +1844,10 @@ netiucv_new_connection(struct net_device *dev, char *username)
|
|||||||
fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
|
fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
|
||||||
conn->next = *clist;
|
conn->next = *clist;
|
||||||
*clist = conn;
|
*clist = conn;
|
||||||
|
write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
|
||||||
}
|
}
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
@ -1835,14 +1859,17 @@ netiucv_new_connection(struct net_device *dev, char *username)
|
|||||||
static void
|
static void
|
||||||
netiucv_remove_connection(struct iucv_connection *conn)
|
netiucv_remove_connection(struct iucv_connection *conn)
|
||||||
{
|
{
|
||||||
struct iucv_connection **clist = &iucv_connections;
|
struct iucv_connection **clist = &iucv_conns.iucv_connections;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
|
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
|
||||||
if (conn == NULL)
|
if (conn == NULL)
|
||||||
return;
|
return;
|
||||||
|
write_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
|
||||||
while (*clist) {
|
while (*clist) {
|
||||||
if (*clist == conn) {
|
if (*clist == conn) {
|
||||||
*clist = conn->next;
|
*clist = conn->next;
|
||||||
|
write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
|
||||||
if (conn->handle) {
|
if (conn->handle) {
|
||||||
iucv_unregister_program(conn->handle);
|
iucv_unregister_program(conn->handle);
|
||||||
conn->handle = NULL;
|
conn->handle = NULL;
|
||||||
@ -1855,6 +1882,7 @@ netiucv_remove_connection(struct iucv_connection *conn)
|
|||||||
}
|
}
|
||||||
clist = &((*clist)->next);
|
clist = &((*clist)->next);
|
||||||
}
|
}
|
||||||
|
write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1947,9 +1975,11 @@ static ssize_t
|
|||||||
conn_write(struct device_driver *drv, const char *buf, size_t count)
|
conn_write(struct device_driver *drv, const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
char username[10];
|
char username[9];
|
||||||
int i, ret;
|
int i, ret;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
|
struct iucv_connection **clist = &iucv_conns.iucv_connections;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
|
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
|
||||||
if (count>9) {
|
if (count>9) {
|
||||||
@ -1960,7 +1990,7 @@ conn_write(struct device_driver *drv, const char *buf, size_t count)
|
|||||||
|
|
||||||
for (i=0, p=(char *)buf; i<8 && *p; i++, p++) {
|
for (i=0, p=(char *)buf; i<8 && *p; i++, p++) {
|
||||||
if (isalnum(*p) || (*p == '$'))
|
if (isalnum(*p) || (*p == '$'))
|
||||||
username[i]= *p;
|
username[i]= toupper(*p);
|
||||||
else if (*p == '\n') {
|
else if (*p == '\n') {
|
||||||
/* trailing lf, grr */
|
/* trailing lf, grr */
|
||||||
break;
|
break;
|
||||||
@ -1971,9 +2001,22 @@ conn_write(struct device_driver *drv, const char *buf, size_t count)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (i<9)
|
while (i<8)
|
||||||
username[i++] = ' ';
|
username[i++] = ' ';
|
||||||
username[9] = '\0';
|
username[8] = '\0';
|
||||||
|
|
||||||
|
read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
|
||||||
|
while (*clist) {
|
||||||
|
if (!strncmp(username, (*clist)->userid, 9))
|
||||||
|
break;
|
||||||
|
clist = &((*clist)->next);
|
||||||
|
}
|
||||||
|
read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
|
||||||
|
if (*clist) {
|
||||||
|
PRINT_WARN("netiucv: Connection to %s already exists\n",
|
||||||
|
username);
|
||||||
|
return -EEXIST;
|
||||||
|
}
|
||||||
dev = netiucv_init_netdevice(username);
|
dev = netiucv_init_netdevice(username);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
PRINT_WARN(
|
PRINT_WARN(
|
||||||
@ -2015,7 +2058,8 @@ DRIVER_ATTR(connection, 0200, NULL, conn_write);
|
|||||||
static ssize_t
|
static ssize_t
|
||||||
remove_write (struct device_driver *drv, const char *buf, size_t count)
|
remove_write (struct device_driver *drv, const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct iucv_connection **clist = &iucv_connections;
|
struct iucv_connection **clist = &iucv_conns.iucv_connections;
|
||||||
|
unsigned long flags;
|
||||||
struct net_device *ndev;
|
struct net_device *ndev;
|
||||||
struct netiucv_priv *priv;
|
struct netiucv_priv *priv;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
@ -2026,7 +2070,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
|
|||||||
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
|
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
|
||||||
|
|
||||||
if (count >= IFNAMSIZ)
|
if (count >= IFNAMSIZ)
|
||||||
count = IFNAMSIZ-1;
|
count = IFNAMSIZ - 1;;
|
||||||
|
|
||||||
for (i=0, p=(char *)buf; i<count && *p; i++, p++) {
|
for (i=0, p=(char *)buf; i<count && *p; i++, p++) {
|
||||||
if ((*p == '\n') || (*p == ' ')) {
|
if ((*p == '\n') || (*p == ' ')) {
|
||||||
@ -2038,6 +2082,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
|
|||||||
}
|
}
|
||||||
name[i] = '\0';
|
name[i] = '\0';
|
||||||
|
|
||||||
|
read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
|
||||||
while (*clist) {
|
while (*clist) {
|
||||||
ndev = (*clist)->netdev;
|
ndev = (*clist)->netdev;
|
||||||
priv = (struct netiucv_priv*)ndev->priv;
|
priv = (struct netiucv_priv*)ndev->priv;
|
||||||
@ -2047,6 +2092,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
|
|||||||
clist = &((*clist)->next);
|
clist = &((*clist)->next);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
|
||||||
if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
|
if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
|
||||||
PRINT_WARN(
|
PRINT_WARN(
|
||||||
"netiucv: net device %s active with peer %s\n",
|
"netiucv: net device %s active with peer %s\n",
|
||||||
@ -2060,6 +2106,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
|
|||||||
netiucv_unregister_device(dev);
|
netiucv_unregister_device(dev);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
|
||||||
PRINT_WARN("netiucv: net device %s unknown\n", name);
|
PRINT_WARN("netiucv: net device %s unknown\n", name);
|
||||||
IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n");
|
IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -2077,8 +2124,8 @@ static void __exit
|
|||||||
netiucv_exit(void)
|
netiucv_exit(void)
|
||||||
{
|
{
|
||||||
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
|
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
|
||||||
while (iucv_connections) {
|
while (iucv_conns.iucv_connections) {
|
||||||
struct net_device *ndev = iucv_connections->netdev;
|
struct net_device *ndev = iucv_conns.iucv_connections->netdev;
|
||||||
struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv;
|
struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv;
|
||||||
struct device *dev = priv->dev;
|
struct device *dev = priv->dev;
|
||||||
|
|
||||||
@ -2120,6 +2167,7 @@ netiucv_init(void)
|
|||||||
if (!ret) {
|
if (!ret) {
|
||||||
ret = driver_create_file(&netiucv_driver, &driver_attr_remove);
|
ret = driver_create_file(&netiucv_driver, &driver_attr_remove);
|
||||||
netiucv_banner();
|
netiucv_banner();
|
||||||
|
rwlock_init(&iucv_conns.iucv_rwlock);
|
||||||
} else {
|
} else {
|
||||||
PRINT_ERR("NETIUCV: failed to add driver attribute.\n");
|
PRINT_ERR("NETIUCV: failed to add driver attribute.\n");
|
||||||
IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret);
|
IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret);
|
||||||
|
Loading…
Reference in New Issue
Block a user