Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
d7d2454a
Commit
d7d2454a
authored
Oct 02, 2002
by
David S. Miller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[EQL]: Rewrite to be SMP safe.
parent
e367aa9a
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
330 additions
and
732 deletions
+330
-732
drivers/net/eql.c
drivers/net/eql.c
+301
-706
include/linux/if_eql.h
include/linux/if_eql.h
+29
-26
No files found.
drivers/net/eql.c
View file @
d7d2454a
...
...
@@ -4,6 +4,7 @@
* (c) Copyright 1995 Simon "Guru Aleph-Null" Janes
* NCM: Network and Communications Management, Inc.
*
* (c) Copyright 2002 David S. Miller (davem@redhat.com)
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
...
...
@@ -107,6 +108,7 @@
* the locking mechanism and timer stuff must be written however,
* this version will not work otherwise
*
* Sorry, I had to rewrite most of this for 2.5.x -DaveM
*/
#include <linux/module.h>
...
...
@@ -121,112 +123,69 @@
#include <asm/uaccess.h>
static
char
version
[]
__initdata
=
"Equalizer1996: $Revision: 1.2.1 $ $Date: 1996/09/22 13:52:00 $ Simon Janes (simon@ncm.com)
\n
"
;
#ifndef EQL_DEBUG
/* #undef EQL_DEBUG -* print nothing at all, not even a boot-banner */
/* #define EQL_DEBUG 1 -* print only the boot-banner */
/* #define EQL_DEBUG 5 -* print major function entries */
/* #define EQL_DEBUG 20 -* print subfunction entries */
/* #define EQL_DEBUG 50 -* print utility entries */
/* #define EQL_DEBUG 100 -* print voluminous function entries */
#define EQL_DEBUG 1
#endif
static
unsigned
int
eql_debug
=
EQL_DEBUG
;
static
int
eql_init
(
struct
net_device
*
dev
);
/* */
static
int
eql_open
(
struct
net_device
*
dev
);
/* */
static
int
eql_close
(
struct
net_device
*
dev
);
/* */
static
int
eql_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
ifr
,
int
cmd
);
/* */
static
int
eql_slave_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
);
/* */
static
struct
net_device_stats
*
eql_get_stats
(
struct
net_device
*
dev
);
/* */
/* ioctl() handlers
---------------- */
static
int
eql_enslave
(
struct
net_device
*
dev
,
slaving_request_t
*
srq
);
/* */
static
int
eql_emancipate
(
struct
net_device
*
dev
,
slaving_request_t
*
srq
);
/* */
static
int
eql_g_slave_cfg
(
struct
net_device
*
dev
,
slave_config_t
*
sc
);
/* */
static
int
eql_s_slave_cfg
(
struct
net_device
*
dev
,
slave_config_t
*
sc
);
/* */
static
int
eql_g_master_cfg
(
struct
net_device
*
dev
,
master_config_t
*
mc
);
/* */
static
int
eql_s_master_cfg
(
struct
net_device
*
dev
,
master_config_t
*
mc
);
/* */
static
inline
int
eql_is_slave
(
struct
net_device
*
dev
);
/* */
static
inline
int
eql_is_master
(
struct
net_device
*
dev
);
/* */
static
slave_t
*
eql_new_slave
(
void
);
/* */
static
void
eql_delete_slave
(
slave_t
*
slave
);
/* */
/* static long eql_slave_priority(slave_t *slave); -* */
static
inline
int
eql_number_slaves
(
slave_queue_t
*
queue
);
/* */
static
int
eql_open
(
struct
net_device
*
dev
);
static
int
eql_close
(
struct
net_device
*
dev
);
static
int
eql_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
ifr
,
int
cmd
);
static
int
eql_slave_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
);
static
struct
net_device_stats
*
eql_get_stats
(
struct
net_device
*
dev
);
static
inline
int
eql_is_empty
(
slave_queue_t
*
queue
);
/* */
static
inline
int
eql_is_full
(
slave_queue_t
*
queue
);
/* */
#define eql_is_slave(dev) ((dev->flags & IFF_SLAVE) == IFF_SLAVE)
#define eql_is_master(dev) ((dev->flags & IFF_MASTER) == IFF_MASTER)
static
slave_queue_t
*
eql_new_slave_queue
(
struct
net_device
*
dev
);
/* */
static
void
eql_delete_slave_queue
(
slave_queue_t
*
queue
);
/* */
static
void
eql_kill_one_slave
(
slave_t
*
slave
);
static
int
eql_insert_slave
(
slave_queue_t
*
queue
,
slave_t
*
slave
);
/* */
static
slave_t
*
eql_remove_slave
(
slave_queue_t
*
queue
,
slave_t
*
slave
);
/* */
/* static int eql_insert_slave_dev(slave_queue_t *queue, struct net_device *dev); -* */
static
int
eql_remove_slave_dev
(
slave_queue_t
*
queue
,
struct
net_device
*
dev
);
/* */
static
void
eql_timer
(
unsigned
long
param
)
{
equalizer_t
*
eql
=
(
equalizer_t
*
)
param
;
struct
list_head
*
this
,
*
tmp
,
*
head
;
static
inline
struct
net_device
*
eql_best_slave_dev
(
slave_queue_t
*
queue
);
/* */
static
inline
slave_t
*
eql_best_slave
(
slave_queue_t
*
queue
);
/* */
static
inline
slave_t
*
eql_first_slave
(
slave_queue_t
*
queue
);
/* */
static
inline
slave_t
*
eql_next_slave
(
slave_queue_t
*
queue
,
slave_t
*
slave
);
/* */
spin_lock_bh
(
&
eql
->
queue
.
lock
);
head
=
&
eql
->
queue
.
all_slaves
;
list_for_each_safe
(
this
,
tmp
,
head
)
{
slave_t
*
slave
=
list_entry
(
this
,
slave_t
,
list
);
static
inline
void
eql_set_best_slave
(
slave_queue_t
*
queue
,
slave_t
*
slave
);
/* */
static
inline
void
eql_schedule_slaves
(
slave_queue_t
*
queue
);
/* */
if
((
slave
->
dev
->
flags
&
IFF_UP
)
==
IFF_UP
)
{
slave
->
bytes_queued
-=
slave
->
priority_Bps
;
if
(
slave
->
bytes_queued
<
0
)
slave
->
bytes_queued
=
0
;
}
else
{
eql_kill_one_slave
(
slave
);
}
static
slave_t
*
eql_find_slave_dev
(
slave_queue_t
*
queue
,
struct
net_device
*
dev
);
/* */
}
spin_unlock_bh
(
&
eql
->
queue
.
lock
);
/* static inline eql_lock_slave_queue(slave_queue_t *queue); -* */
/* static inline eql_unlock_slave_queue(slave_queue_t *queue); -* */
eql
->
timer
.
expires
=
jiffies
+
EQL_DEFAULT_RESCHED_IVAL
;
add_timer
(
&
eql
->
timer
);
}
static
void
eql_timer
(
unsigned
long
param
);
/* */
/* struct net_device * interface functions
---------------------------------------------------------
*/
static
char
version
[]
__initdata
=
"Equalizer2002: Simon Janes (simon@ncm.com) and David S. Miller (davem@redhat.com)
\n
"
;
static
int
__init
eql_init
(
struct
net_device
*
dev
)
{
static
unsigned
version_printed
;
/* static unsigned num_masters = 0; */
equalizer_t
*
eql
=
0
;
static
unsigned
int
version_printed
;
equalizer_t
*
eql
;
SET_MODULE_OWNER
(
dev
);
if
(
version_printed
++
==
0
&&
eql_debug
>
0
)
if
(
version_printed
++
==
0
)
printk
(
version
);
/*
* Initialize the device structure.
*/
dev
->
priv
=
kmalloc
(
sizeof
(
equalizer_t
),
GFP_KERNEL
);
dev
->
priv
=
kmalloc
(
sizeof
(
equalizer_t
),
GFP_KERNEL
);
if
(
dev
->
priv
==
NULL
)
return
-
ENOMEM
;
memset
(
dev
->
priv
,
0
,
sizeof
(
equalizer_t
));
eql
=
(
equalizer_t
*
)
dev
->
priv
;
eql
->
stats
=
kmalloc
(
sizeof
(
struct
net_device_stats
),
GFP_KERNEL
);
if
(
eql
->
stats
==
NULL
)
{
kfree
(
dev
->
priv
);
dev
->
priv
=
NULL
;
return
-
ENOMEM
;
}
memset
(
eql
->
stats
,
0
,
sizeof
(
struct
net_device_stats
));
memset
(
dev
->
priv
,
0
,
sizeof
(
equalizer_t
));
eql
=
dev
->
priv
;
init_timer
(
&
eql
->
timer
);
init_timer
(
&
eql
->
timer
);
eql
->
timer
.
data
=
(
unsigned
long
)
dev
->
priv
;
eql
->
timer
.
expires
=
jiffies
+
EQL_DEFAULT_RESCHED_IVAL
;
eql
->
timer
.
function
=
&
eql_timer
;
eql
->
timer_on
=
0
;
eql
->
timer
.
expires
=
jiffies
+
EQL_DEFAULT_RESCHED_IVAL
;
eql
->
timer
.
function
=
eql_timer
;
spin_lock_init
(
&
eql
->
queue
.
lock
);
INIT_LIST_HEAD
(
&
eql
->
queue
.
all_slaves
);
eql
->
queue
.
master_dev
=
dev
;
dev
->
open
=
eql_open
;
dev
->
stop
=
eql_close
;
...
...
@@ -234,17 +193,12 @@ static int __init eql_init(struct net_device *dev)
dev
->
hard_start_xmit
=
eql_slave_xmit
;
dev
->
get_stats
=
eql_get_stats
;
/*
* Fill in the fields of the device structure with
* eql-generic values.
*/
/*
* Now we undo some of the things that eth_setup does
* that we don't like
*/
dev
->
mtu
=
EQL_DEFAULT_MTU
;
/* set to 576 in eql.h */
dev
->
mtu
=
EQL_DEFAULT_MTU
;
/* set to 576 in
if_
eql.h */
dev
->
flags
=
IFF_MASTER
;
dev
->
type
=
ARPHRD_SLIP
;
...
...
@@ -255,257 +209,330 @@ static int __init eql_init(struct net_device *dev)
static
int
eql_open
(
struct
net_device
*
dev
)
{
equalizer_t
*
eql
=
(
equalizer_t
*
)
dev
->
priv
;
slave_queue_t
*
new_queue
;
equalizer_t
*
eql
=
dev
->
priv
;
#ifdef EQL_DEBUG
if
(
eql_debug
>=
5
)
printk
(
"%s: open
\n
"
,
dev
->
name
);
#endif
/* XXX We should force this off automatically for the user. */
printk
(
KERN_INFO
"%s: remember to turn off Van-Jacobson compression on "
"your slave devices.
\n
"
,
dev
->
name
);
printk
(
"%s: remember to turn off Van-Jacobson compression on your slave devices.
\n
"
,
dev
->
name
);
if
(
!
list_empty
(
&
eql
->
queue
.
all_slaves
))
BUG
();
new_queue
=
eql_new_slave_queue
(
dev
);
if
(
new_queue
!=
0
)
{
new_queue
->
master_dev
=
dev
;
eql
->
queue
=
new_queue
;
eql
->
queue
->
lock
=
0
;
eql
->
min_slaves
=
1
;
eql
->
max_slaves
=
EQL_DEFAULT_MAX_SLAVES
;
/* 4 usually... */
printk
(
"%s: adding timer
\n
"
,
dev
->
name
);
eql
->
timer_on
=
1
;
add_timer
(
&
eql
->
timer
);
add_timer
(
&
eql
->
timer
);
return
0
;
}
return
-
ENOMEM
;
}
static
void
eql_kill_one_slave
(
slave_t
*
slave
)
{
list_del
(
&
slave
->
list
);
slave
->
dev
->
flags
&=
~
IFF_SLAVE
;
dev_put
(
slave
->
dev
);
kfree
(
slave
);
}
static
void
eql_kill_slave_queue
(
slave_queue_t
*
queue
)
{
struct
list_head
*
head
,
*
tmp
,
*
this
;
spin_lock_bh
(
&
queue
->
lock
);
head
=
&
queue
->
all_slaves
;
list_for_each_safe
(
this
,
tmp
,
head
)
{
slave_t
*
s
=
list_entry
(
this
,
slave_t
,
list
);
eql_kill_one_slave
(
s
);
queue
->
num_slaves
--
;
}
spin_unlock_bh
(
&
queue
->
lock
);
}
static
int
eql_close
(
struct
net_device
*
dev
)
{
equalizer_t
*
eql
=
(
equalizer_t
*
)
dev
->
priv
;
equalizer_t
*
eql
=
dev
->
priv
;
#ifdef EQL_DEBUG
if
(
eql_debug
>=
5
)
printk
(
"%s: close
\n
"
,
dev
->
name
);
#endif
/*
* The timer has to be stopped first before we start hacking away
* at the data structure it scans every so often...
*/
#ifdef EQL_DEBUG
printk
(
"%s: stopping timer
\n
"
,
dev
->
name
);
#endif
eql
->
timer_on
=
0
;
del_timer
(
&
eql
->
timer
);
del_timer_sync
(
&
eql
->
timer
);
eql_
delete_slave_queue
(
eql
->
queue
);
eql_
kill_slave_queue
(
&
eql
->
queue
);
return
0
;
}
static
int
eql_enslave
(
struct
net_device
*
dev
,
slaving_request_t
*
srq
);
static
int
eql_emancipate
(
struct
net_device
*
dev
,
slaving_request_t
*
srq
);
static
int
eql_g_slave_cfg
(
struct
net_device
*
dev
,
slave_config_t
*
sc
);
static
int
eql_s_slave_cfg
(
struct
net_device
*
dev
,
slave_config_t
*
sc
);
static
int
eql_g_master_cfg
(
struct
net_device
*
dev
,
master_config_t
*
mc
);
static
int
eql_s_master_cfg
(
struct
net_device
*
dev
,
master_config_t
*
mc
);
static
int
eql_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
ifr
,
int
cmd
)
{
if
(
cmd
!=
EQL_GETMASTRCFG
&&
cmd
!=
EQL_GETSLAVECFG
&&
if
(
cmd
!=
EQL_GETMASTRCFG
&&
cmd
!=
EQL_GETSLAVECFG
&&
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
switch
(
cmd
)
{
switch
(
cmd
)
{
case
EQL_ENSLAVE
:
return
eql_enslave
(
dev
,
(
slaving_request_t
*
)
ifr
->
ifr_data
);
return
eql_enslave
(
dev
,
(
slaving_request_t
*
)
ifr
->
ifr_data
);
case
EQL_EMANCIPATE
:
return
eql_emancipate
(
dev
,
(
slaving_request_t
*
)
ifr
->
ifr_data
);
return
eql_emancipate
(
dev
,
(
slaving_request_t
*
)
ifr
->
ifr_data
);
case
EQL_GETSLAVECFG
:
return
eql_g_slave_cfg
(
dev
,
(
slave_config_t
*
)
ifr
->
ifr_data
);
return
eql_g_slave_cfg
(
dev
,
(
slave_config_t
*
)
ifr
->
ifr_data
);
case
EQL_SETSLAVECFG
:
return
eql_s_slave_cfg
(
dev
,
(
slave_config_t
*
)
ifr
->
ifr_data
);
return
eql_s_slave_cfg
(
dev
,
(
slave_config_t
*
)
ifr
->
ifr_data
);
case
EQL_GETMASTRCFG
:
return
eql_g_master_cfg
(
dev
,
(
master_config_t
*
)
ifr
->
ifr_data
);
return
eql_g_master_cfg
(
dev
,
(
master_config_t
*
)
ifr
->
ifr_data
);
case
EQL_SETMASTRCFG
:
return
eql_s_master_cfg
(
dev
,
(
master_config_t
*
)
ifr
->
ifr_data
);
return
eql_s_master_cfg
(
dev
,
(
master_config_t
*
)
ifr
->
ifr_data
);
default:
return
-
EOPNOTSUPP
;
}
}
;
}
/* queue->lock must be held */
static
slave_t
*
__eql_schedule_slaves
(
slave_queue_t
*
queue
)
{
unsigned
long
best_load
=
~
0UL
;
struct
list_head
*
this
,
*
tmp
,
*
head
;
slave_t
*
best_slave
;
best_slave
=
NULL
;
/* Make a pass to set the best slave. */
head
=
&
queue
->
all_slaves
;
list_for_each_safe
(
this
,
tmp
,
head
)
{
slave_t
*
slave
=
list_entry
(
this
,
slave_t
,
list
);
unsigned
long
slave_load
,
bytes_queued
,
priority_Bps
;
/* Go through the slave list once, updating best_slave
* whenever a new best_load is found.
*/
bytes_queued
=
slave
->
bytes_queued
;
priority_Bps
=
slave
->
priority_Bps
;
if
((
slave
->
dev
->
flags
&
IFF_UP
)
==
IFF_UP
)
{
slave_load
=
(
~
0UL
-
(
~
0UL
/
2
))
-
(
priority_Bps
)
+
bytes_queued
*
8
;
if
(
slave_load
<
best_load
)
{
best_load
=
slave_load
;
best_slave
=
slave
;
}
}
else
{
/* We found a dead slave, kill it. */
eql_kill_one_slave
(
slave
);
}
}
return
best_slave
;
}
static
int
eql_slave_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
equalizer_t
*
eql
=
(
equalizer_t
*
)
dev
->
priv
;
struct
net_device
*
slave_dev
=
0
;
equalizer_t
*
eql
=
dev
->
priv
;
slave_t
*
slave
;
if
(
skb
==
NULL
)
return
0
;
eql_schedule_slaves
(
eql
->
queue
);
spin_lock
(
&
eql
->
queue
.
lock
);
slave
=
eql_best_slave
(
eql
->
queue
);
slave_dev
=
slave
?
slave
->
dev
:
0
;
slave
=
__eql_schedule_slaves
(
&
eql
->
queue
);
if
(
slave
)
{
struct
net_device
*
slave_dev
=
slave
->
dev
;
if
(
slave_dev
!=
0
)
{
#ifdef EQL_DEBUG
if
(
eql_debug
>=
100
)
printk
(
"%s: %d slaves xmitng %d B %s
\n
"
,
dev
->
name
,
eql_number_slaves
(
eql
->
queue
),
skb
->
len
,
slave_dev
->
name
);
#endif
skb
->
dev
=
slave_dev
;
skb
->
priority
=
1
;
slave
->
bytes_queued
+=
skb
->
len
;
dev_queue_xmit
(
skb
);
eql
->
stats
->
tx_packets
++
;
}
else
{
/*
* The alternative for this is the return 1 and have
* dev_queue_xmit just queue it up on the eql's queue.
*/
eql
->
stats
->
tx_dropped
++
;
dev_queue_xmit
(
skb
);
eql
->
stats
.
tx_packets
++
;
}
else
{
eql
->
stats
.
tx_dropped
++
;
dev_kfree_skb
(
skb
);
}
spin_unlock
(
&
eql
->
queue
.
lock
);
return
0
;
}
static
struct
net_device_stats
*
eql_get_stats
(
struct
net_device
*
dev
)
{
equalizer_t
*
eql
=
(
equalizer_t
*
)
dev
->
priv
;
return
eql
->
stats
;
equalizer_t
*
eql
=
dev
->
priv
;
return
&
eql
->
stats
;
}
/*
* Private ioctl functions
*/
static
int
eql_enslave
(
struct
net_device
*
dev
,
slaving_request_t
*
srqp
)
/* queue->lock must be held */
static
slave_t
*
__eql_find_slave_dev
(
slave_queue_t
*
queue
,
struct
net_device
*
dev
)
{
struct
list_head
*
this
,
*
head
;
head
=
&
queue
->
all_slaves
;
list_for_each
(
this
,
head
)
{
slave_t
*
slave
=
list_entry
(
this
,
slave_t
,
list
);
if
(
slave
->
dev
==
dev
)
return
slave
;
}
return
NULL
;
}
static
inline
int
eql_is_full
(
slave_queue_t
*
queue
)
{
equalizer_t
*
eql
=
queue
->
master_dev
->
priv
;
if
(
queue
->
num_slaves
>=
eql
->
max_slaves
)
return
1
;
return
0
;
}
/* queue->lock must be held */
static
int
__eql_insert_slave
(
slave_queue_t
*
queue
,
slave_t
*
slave
)
{
if
(
!
eql_is_full
(
queue
))
{
slave_t
*
duplicate_slave
=
0
;
duplicate_slave
=
__eql_find_slave_dev
(
queue
,
slave
->
dev
);
if
(
duplicate_slave
!=
0
)
eql_kill_one_slave
(
duplicate_slave
);
list_add
(
&
slave
->
list
,
&
queue
->
all_slaves
);
queue
->
num_slaves
++
;
slave
->
dev
->
flags
|=
IFF_SLAVE
;
return
0
;
}
return
-
ENOSPC
;
}
static
int
eql_enslave
(
struct
net_device
*
master_dev
,
slaving_request_t
*
srqp
)
{
struct
net_device
*
master_dev
;
struct
net_device
*
slave_dev
;
slaving_request_t
srq
;
if
(
copy_from_user
(
&
srq
,
srqp
,
sizeof
(
slaving_request_t
)))
{
#ifdef EQL_DEBUG
if
(
eql_debug
>=
20
)
printk
(
"EQL enslave: error detected by copy_from_user
\n
"
);
#endif
return
-
EFAULT
;
}
#ifdef EQL_DEBUG
if
(
eql_debug
>=
20
)
printk
(
"%s: enslave '%s' %ld bps
\n
"
,
dev
->
name
,
srq
.
slave_name
,
srq
.
priority
);
#endif
master_dev
=
dev
;
/* for "clarity" */
slave_dev
=
__dev_get_by_name
(
srq
.
slave_name
);
if
(
master_dev
!=
0
&&
slave_dev
!=
0
)
{
if
((
master_dev
->
flags
&
IFF_UP
)
==
IFF_UP
)
{
/*slave is not a master & not already a slave:*/
if
(
!
eql_is_master
(
slave_dev
)
&&
!
eql_is_slave
(
slave_dev
)
)
{
slave_t
*
s
=
eql_new_slave
();
equalizer_t
*
eql
=
(
equalizer_t
*
)
master_dev
->
priv
;
if
(
!
s
)
slave_dev
=
dev_get_by_name
(
srq
.
slave_name
);
if
(
slave_dev
)
{
if
((
master_dev
->
flags
&
IFF_UP
)
==
IFF_UP
)
{
/* slave is not a master & not already a slave: */
if
(
!
eql_is_master
(
slave_dev
)
&&
!
eql_is_slave
(
slave_dev
))
{
slave_t
*
s
=
kmalloc
(
sizeof
(
*
s
),
GFP_KERNEL
);
equalizer_t
*
eql
=
master_dev
->
priv
;
int
ret
;
if
(
!
s
)
{
dev_put
(
slave_dev
);
return
-
ENOMEM
;
}
memset
(
s
,
0
,
sizeof
(
*
s
));
s
->
dev
=
slave_dev
;
s
->
priority
=
srq
.
priority
;
s
->
priority_bps
=
srq
.
priority
;
s
->
priority_Bps
=
srq
.
priority
/
8
;
slave_dev
->
flags
|=
IFF_SLAVE
;
eql_insert_slave
(
eql
->
queue
,
s
);
return
0
;
spin_lock_bh
(
&
eql
->
queue
.
lock
);
ret
=
__eql_insert_slave
(
&
eql
->
queue
,
s
);
if
(
ret
)
{
dev_put
(
slave_dev
);
kfree
(
s
);
}
spin_unlock_bh
(
&
eql
->
queue
.
lock
);
return
ret
;
}
#ifdef EQL_DEBUG
else
if
(
eql_debug
>=
20
)
printk
(
"EQL enslave: slave is master or slave is already slave
\n
"
);
#endif
}
#ifdef EQL_DEBUG
else
if
(
eql_debug
>=
20
)
printk
(
"EQL enslave: master device not up!
\n
"
);
#endif
dev_put
(
slave_dev
);
}
#ifdef EQL_DEBUG
else
if
(
eql_debug
>=
20
)
printk
(
"EQL enslave: master or slave are NULL"
);
#endif
return
-
EINVAL
;
}
static
int
eql_emancipate
(
struct
net_device
*
dev
,
slaving_request_t
*
srqp
)
static
int
eql_emancipate
(
struct
net_device
*
master_
dev
,
slaving_request_t
*
srqp
)
{
struct
net_device
*
master_de
v
;
equalizer_t
*
eql
=
master_dev
->
pri
v
;
struct
net_device
*
slave_dev
;
slaving_request_t
srq
;
int
ret
;
if
(
copy_from_user
(
&
srq
,
srqp
,
sizeof
(
slaving_request_t
)))
return
-
EFAULT
;
#ifdef EQL_DEBUG
if
(
eql_debug
>=
20
)
printk
(
"%s: emancipate `%s`
\n
"
,
dev
->
name
,
srq
.
slave_name
);
#endif
master_dev
=
dev
;
/* for "clarity" */
slave_dev
=
__dev_get_by_name
(
srq
.
slave_name
);
if
(
eql_is_slave
(
slave_dev
)
)
/* really is a slave */
{
equalizer_t
*
eql
=
(
equalizer_t
*
)
master_dev
->
priv
;
slave_dev
->
flags
=
slave_dev
->
flags
&
~
IFF_SLAVE
;
eql_remove_slave_dev
(
eql
->
queue
,
slave_dev
);
return
0
;
slave_dev
=
dev_get_by_name
(
srq
.
slave_name
);
ret
=
-
EINVAL
;
if
(
slave_dev
)
{
spin_lock_bh
(
&
eql
->
queue
.
lock
);
if
(
eql_is_slave
(
slave_dev
))
{
slave_t
*
slave
=
__eql_find_slave_dev
(
&
eql
->
queue
,
slave_dev
);
if
(
slave
)
{
eql_kill_one_slave
(
slave
);
ret
=
0
;
}
}
dev_put
(
slave_dev
);
spin_unlock_bh
(
&
eql
->
queue
.
lock
);
}
return
-
EINVAL
;
}
return
ret
;
}
static
int
eql_g_slave_cfg
(
struct
net_device
*
dev
,
slave_config_t
*
scp
)
{
equalizer_t
*
eql
=
dev
->
priv
;
slave_t
*
slave
;
equalizer_t
*
eql
;
struct
net_device
*
slave_dev
;
slave_config_t
sc
;
int
ret
;
if
(
copy_from_user
(
&
sc
,
scp
,
sizeof
(
slave_config_t
)))
if
(
copy_from_user
(
&
sc
,
scp
,
sizeof
(
slave_config_t
)))
return
-
EFAULT
;
#ifdef EQL_DEBUG
if
(
eql_debug
>=
20
)
printk
(
"%s: get config for slave `%s'
\n
"
,
dev
->
name
,
sc
.
slave_name
);
#endif
eql
=
(
equalizer_t
*
)
dev
->
priv
;
slave_dev
=
__dev_get_by_name
(
sc
.
slave_name
);
if
(
eql_is_slave
(
slave_dev
)
)
{
slave
=
eql_find_slave_dev
(
eql
->
queue
,
slave_dev
);
if
(
slave
!=
0
)
{
slave_dev
=
dev_get_by_name
(
sc
.
slave_name
);
ret
=
-
EINVAL
;
spin_lock_bh
(
&
eql
->
queue
.
lock
);
if
(
eql_is_slave
(
slave_dev
))
{
slave
=
__eql_find_slave_dev
(
&
eql
->
queue
,
slave_dev
);
if
(
slave
)
{
sc
.
priority
=
slave
->
priority
;
if
(
copy_to_user
(
scp
,
&
sc
,
sizeof
(
slave_config_t
)))
return
-
EFAULT
;
return
0
;
ret
=
0
;
}
}
return
-
EINVAL
;
}
spin_unlock_bh
(
&
eql
->
queue
.
lock
);
dev_put
(
slave_dev
);
if
(
!
ret
&&
copy_to_user
(
scp
,
&
sc
,
sizeof
(
slave_config_t
)))
ret
=
-
EFAULT
;
return
ret
;
}
static
int
eql_s_slave_cfg
(
struct
net_device
*
dev
,
slave_config_t
*
scp
)
{
...
...
@@ -513,71 +540,57 @@ static int eql_s_slave_cfg(struct net_device *dev, slave_config_t *scp)
equalizer_t
*
eql
;
struct
net_device
*
slave_dev
;
slave_config_t
sc
;
int
ret
;
if
(
copy_from_user
(
&
sc
,
scp
,
sizeof
(
slave_config_t
)))
if
(
copy_from_user
(
&
sc
,
scp
,
sizeof
(
slave_config_t
)))
return
-
EFAULT
;
#ifdef EQL_DEBUG
if
(
eql_debug
>=
20
)
printk
(
"%s: set config for slave `%s'
\n
"
,
dev
->
name
,
sc
.
slave_name
);
#endif
eql
=
dev
->
priv
;
slave_dev
=
dev_get_by_name
(
sc
.
slave_name
);
eql
=
(
equalizer_t
*
)
dev
->
priv
;
slave_dev
=
__dev_get_by_name
(
sc
.
slave_name
);
ret
=
-
EINVAL
;
if
(
eql_is_slave
(
slave_dev
)
)
{
slave
=
eql_find_slave_dev
(
eql
->
queue
,
slave_dev
);
if
(
slave
!=
0
)
{
spin_lock_bh
(
&
eql
->
queue
.
lock
);
if
(
eql_is_slave
(
slave_dev
))
{
slave
=
__eql_find_slave_dev
(
&
eql
->
queue
,
slave_dev
);
if
(
slave
)
{
slave
->
priority
=
sc
.
priority
;
slave
->
priority_bps
=
sc
.
priority
;
slave
->
priority_Bps
=
sc
.
priority
/
8
;
ret
urn
0
;
ret
=
0
;
}
}
return
-
EINVAL
;
}
spin_unlock_bh
(
&
eql
->
queue
.
lock
);
return
ret
;
}
static
int
eql_g_master_cfg
(
struct
net_device
*
dev
,
master_config_t
*
mcp
)
{
equalizer_t
*
eql
;
master_config_t
mc
;
#if EQL_DEBUG
if
(
eql_debug
>=
20
)
printk
(
"%s: get master config
\n
"
,
dev
->
name
);
#endif
if
(
eql_is_master
(
dev
)
)
{
eql
=
(
equalizer_t
*
)
dev
->
priv
;
if
(
eql_is_master
(
dev
))
{
eql
=
dev
->
priv
;
mc
.
max_slaves
=
eql
->
max_slaves
;
mc
.
min_slaves
=
eql
->
min_slaves
;
if
(
copy_to_user
(
mcp
,
&
mc
,
sizeof
(
master_config_t
)))
if
(
copy_to_user
(
mcp
,
&
mc
,
sizeof
(
master_config_t
)))
return
-
EFAULT
;
return
0
;
}
return
-
EINVAL
;
}
static
int
eql_s_master_cfg
(
struct
net_device
*
dev
,
master_config_t
*
mcp
)
{
equalizer_t
*
eql
;
master_config_t
mc
;
if
(
copy_from_user
(
&
mc
,
mcp
,
sizeof
(
master_config_t
)))
if
(
copy_from_user
(
&
mc
,
mcp
,
sizeof
(
master_config_t
)))
return
-
EFAULT
;
#if EQL_DEBUG
if
(
eql_debug
>=
20
)
printk
(
"%s: set master config
\n
"
,
dev
->
name
);
#endif
if
(
eql_is_master
(
dev
)
)
{
eql
=
(
equalizer_t
*
)
dev
->
priv
;
if
(
eql_is_master
(
dev
))
{
eql
=
dev
->
priv
;
eql
->
max_slaves
=
mc
.
max_slaves
;
eql
->
min_slaves
=
mc
.
min_slaves
;
return
0
;
...
...
@@ -585,415 +598,6 @@ static int eql_s_master_cfg(struct net_device *dev, master_config_t *mcp)
return
-
EINVAL
;
}
/*
* Private device support functions
*/
static
inline
int
eql_is_slave
(
struct
net_device
*
dev
)
{
if
(
dev
)
{
if
((
dev
->
flags
&
IFF_SLAVE
)
==
IFF_SLAVE
)
return
1
;
}
return
0
;
}
static
inline
int
eql_is_master
(
struct
net_device
*
dev
)
{
if
(
dev
)
{
if
((
dev
->
flags
&
IFF_MASTER
)
==
IFF_MASTER
)
return
1
;
}
return
0
;
}
static
slave_t
*
eql_new_slave
(
void
)
{
slave_t
*
slave
;
slave
=
(
slave_t
*
)
kmalloc
(
sizeof
(
slave_t
),
GFP_KERNEL
);
if
(
slave
)
memset
(
slave
,
0
,
sizeof
(
slave_t
));
return
slave
;
}
static
void
eql_delete_slave
(
slave_t
*
slave
)
{
kfree
(
slave
);
}
#if 0 /* not currently used, will be used
when we really use a priority queue */
static long slave_Bps(slave_t *slave)
{
return (slave->priority_Bps);
}
static long slave_bps(slave_t *slave)
{
return (slave->priority_bps);
}
#endif
static
inline
int
eql_number_slaves
(
slave_queue_t
*
queue
)
{
return
queue
->
num_slaves
;
}
static
inline
int
eql_is_empty
(
slave_queue_t
*
queue
)
{
if
(
eql_number_slaves
(
queue
)
==
0
)
return
1
;
return
0
;
}
static
inline
int
eql_is_full
(
slave_queue_t
*
queue
)
{
equalizer_t
*
eql
=
(
equalizer_t
*
)
queue
->
master_dev
->
priv
;
if
(
eql_number_slaves
(
queue
)
==
eql
->
max_slaves
)
return
1
;
return
0
;
}
static
slave_queue_t
*
eql_new_slave_queue
(
struct
net_device
*
dev
)
{
slave_queue_t
*
queue
;
slave_t
*
head_slave
;
slave_t
*
tail_slave
;
queue
=
(
slave_queue_t
*
)
kmalloc
(
sizeof
(
slave_queue_t
),
GFP_KERNEL
);
if
(
!
queue
)
goto
err_out
;
head_slave
=
eql_new_slave
();
if
(
!
head_slave
)
goto
err_out_queue
;
tail_slave
=
eql_new_slave
();
if
(
!
tail_slave
)
goto
err_out_hs
;
memset
(
queue
,
0
,
sizeof
(
slave_queue_t
));
head_slave
->
next
=
tail_slave
;
tail_slave
->
next
=
0
;
queue
->
head
=
head_slave
;
queue
->
num_slaves
=
0
;
queue
->
master_dev
=
dev
;
return
queue
;
err_out_hs:
kfree
(
head_slave
);
err_out_queue:
kfree
(
queue
);
err_out:
return
NULL
;
}
static
void
eql_delete_slave_queue
(
slave_queue_t
*
queue
)
{
slave_t
*
zapped
;
/*
* This should only be called when there isn't a
* timer running that scans the data periodically..
* dev_close stops the timer...
*/
while
(
!
eql_is_empty
(
queue
)
)
{
zapped
=
eql_remove_slave
(
queue
,
queue
->
head
->
next
);
eql_delete_slave
(
zapped
);
}
kfree
(
queue
->
head
->
next
);
kfree
(
queue
->
head
);
kfree
(
queue
);
}
static
int
eql_insert_slave
(
slave_queue_t
*
queue
,
slave_t
*
slave
)
{
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
if
(
!
eql_is_full
(
queue
)
)
{
slave_t
*
duplicate_slave
=
0
;
duplicate_slave
=
eql_find_slave_dev
(
queue
,
slave
->
dev
);
if
(
duplicate_slave
!=
0
)
{
/* printk ("%s: found a duplicate, killing it and replacing\n",
queue->master_dev->name); */
eql_delete_slave
(
eql_remove_slave
(
queue
,
duplicate_slave
));
}
slave
->
next
=
queue
->
head
->
next
;
queue
->
head
->
next
=
slave
;
queue
->
num_slaves
++
;
restore_flags
(
flags
);
return
0
;
}
restore_flags
(
flags
);
return
1
;
}
static
slave_t
*
eql_remove_slave
(
slave_queue_t
*
queue
,
slave_t
*
slave
)
{
slave_t
*
prev
;
slave_t
*
curr
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
prev
=
queue
->
head
;
curr
=
queue
->
head
->
next
;
while
(
curr
!=
slave
&&
curr
->
dev
!=
0
)
{
/* printk ("%s: remove_slave; searching...\n", queue->master_dev->name); */
prev
=
curr
;
curr
=
curr
->
next
;
}
if
(
curr
==
slave
)
{
prev
->
next
=
curr
->
next
;
queue
->
num_slaves
--
;
curr
->
dev
->
flags
=
curr
->
dev
->
flags
&
~
IFF_SLAVE
;
restore_flags
(
flags
);
return
curr
;
}
restore_flags
(
flags
);
return
0
;
/* not found */
}
static
int
eql_remove_slave_dev
(
slave_queue_t
*
queue
,
struct
net_device
*
dev
)
{
slave_t
*
prev
;
slave_t
*
curr
;
slave_t
*
target
;
target
=
eql_find_slave_dev
(
queue
,
dev
);
if
(
target
!=
0
)
{
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
prev
=
queue
->
head
;
curr
=
prev
->
next
;
while
(
curr
!=
target
)
{
prev
=
curr
;
curr
=
curr
->
next
;
}
prev
->
next
=
curr
->
next
;
queue
->
num_slaves
--
;
restore_flags
(
flags
);
eql_delete_slave
(
curr
);
return
0
;
}
return
1
;
}
static
inline
struct
net_device
*
eql_best_slave_dev
(
slave_queue_t
*
queue
)
{
if
(
queue
->
best_slave
!=
0
)
{
if
(
queue
->
best_slave
->
dev
!=
0
)
return
queue
->
best_slave
->
dev
;
else
return
0
;
}
else
return
0
;
}
static
inline
slave_t
*
eql_best_slave
(
slave_queue_t
*
queue
)
{
return
queue
->
best_slave
;
}
static
inline
void
eql_schedule_slaves
(
slave_queue_t
*
queue
)
{
struct
net_device
*
master_dev
=
queue
->
master_dev
;
slave_t
*
best_slave
=
0
;
slave_t
*
slave_corpse
=
0
;
#ifdef EQL_DEBUG
if
(
eql_debug
>=
100
)
printk
(
"%s: schedule %d slaves
\n
"
,
master_dev
->
name
,
eql_number_slaves
(
queue
));
#endif
if
(
eql_is_empty
(
queue
)
)
{
/*
* No slaves to play with
*/
eql_set_best_slave
(
queue
,
(
slave_t
*
)
0
);
return
;
}
else
{
/*
* Make a pass to set the best slave
*/
unsigned
long
best_load
=
(
unsigned
long
)
ULONG_MAX
;
slave_t
*
slave
=
0
;
unsigned
long
flags
;
int
i
;
save_flags
(
flags
);
cli
();
for
(
i
=
1
,
slave
=
eql_first_slave
(
queue
);
i
<=
eql_number_slaves
(
queue
);
i
++
,
slave
=
eql_next_slave
(
queue
,
slave
))
{
/*
* Go through the slave list once, updating best_slave
* whenever a new best_load is found, whenever a dead
* slave is found, it is marked to be pulled out of the
* queue
*/
unsigned
long
slave_load
;
unsigned
long
bytes_queued
;
unsigned
long
priority_Bps
;
if
(
slave
!=
0
)
{
bytes_queued
=
slave
->
bytes_queued
;
priority_Bps
=
slave
->
priority_Bps
;
if
(
slave
->
dev
!=
0
)
{
if
((
slave
->
dev
->
flags
&
IFF_UP
)
==
IFF_UP
)
{
slave_load
=
(
ULONG_MAX
-
(
ULONG_MAX
/
2
))
-
(
priority_Bps
)
+
bytes_queued
*
8
;
if
(
slave_load
<
best_load
)
{
best_load
=
slave_load
;
best_slave
=
slave
;
}
}
else
/* we found a dead slave */
{
/*
* We only bury one slave at a time, if more than
* one slave dies, we will bury him on the next
* reschedule. slaves don't die all at once that
* much anyway
*/
slave_corpse
=
slave
;
}
}
}
}
/* for */
restore_flags
(
flags
);
eql_set_best_slave
(
queue
,
best_slave
);
}
/* else */
if
(
slave_corpse
!=
0
)
{
printk
(
"eql: scheduler found dead slave, burying...
\n
"
);
eql_delete_slave
(
eql_remove_slave
(
queue
,
slave_corpse
));
}
return
;
}
static
slave_t
*
eql_find_slave_dev
(
slave_queue_t
*
queue
,
struct
net_device
*
dev
)
{
slave_t
*
slave
=
0
;
slave
=
eql_first_slave
(
queue
);
while
(
slave
!=
0
&&
slave
->
dev
!=
dev
&&
slave
!=
0
)
{
#if 0
if (slave->dev != 0)
printk ("eql: find_slave_dev; looked at '%s'...\n", slave->dev->name);
else
printk ("eql: find_slave_dev; looked at nothing...\n");
#endif
slave
=
slave
->
next
;
}
return
slave
;
}
static
inline
slave_t
*
eql_first_slave
(
slave_queue_t
*
queue
)
{
return
queue
->
head
->
next
;
}
static
inline
slave_t
*
eql_next_slave
(
slave_queue_t
*
queue
,
slave_t
*
slave
)
{
return
slave
->
next
;
}
static
inline
void
eql_set_best_slave
(
slave_queue_t
*
queue
,
slave_t
*
slave
)
{
queue
->
best_slave
=
slave
;
}
static
void
eql_timer
(
unsigned
long
param
)
{
equalizer_t
*
eql
=
(
equalizer_t
*
)
param
;
slave_t
*
slave
;
slave_t
*
slave_corpse
=
0
;
int
i
;
unsigned
long
flags
;
if
(
!
eql_is_empty
(
eql
->
queue
)
)
{
save_flags
(
flags
);
cli
();
for
(
i
=
1
,
slave
=
eql_first_slave
(
eql
->
queue
);
i
<=
eql_number_slaves
(
eql
->
queue
);
i
++
,
slave
=
eql_next_slave
(
eql
->
queue
,
slave
))
{
if
(
slave
!=
0
)
{
if
((
slave
->
dev
->
flags
&
IFF_UP
)
==
IFF_UP
)
{
slave
->
bytes_queued
-=
slave
->
priority_Bps
;
if
(
slave
->
bytes_queued
<
0
)
slave
->
bytes_queued
=
0
;
}
else
slave_corpse
=
slave
;
}
}
restore_flags
(
flags
);
if
(
slave_corpse
!=
0
)
{
printk
(
"eql: timer found dead slave, burying...
\n
"
);
eql_delete_slave
(
eql_remove_slave
(
eql
->
queue
,
slave_corpse
));
}
}
if
(
eql
->
timer_on
!=
0
)
{
eql
->
timer
.
expires
=
jiffies
+
EQL_DEFAULT_RESCHED_IVAL
;
add_timer
(
&
eql
->
timer
);
}
}
static
struct
net_device
dev_eql
;
static
int
__init
eql_init_module
(
void
)
...
...
@@ -1009,7 +613,6 @@ static int __init eql_init_module(void)
static
void
__exit
eql_cleanup_module
(
void
)
{
kfree
(((
equalizer_t
*
)
dev_eql
.
priv
)
->
stats
);
kfree
(
dev_eql
.
priv
);
unregister_netdev
(
&
dev_eql
);
}
...
...
@@ -1017,11 +620,3 @@ static void __exit eql_cleanup_module(void)
module_init
(
eql_init_module
);
module_exit
(
eql_cleanup_module
);
MODULE_LICENSE
(
"GPL"
);
/*
* Local Variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c eql.c"
* version-control: t
* kept-new-versions: 20
* End:
*/
include/linux/if_eql.h
View file @
d7d2454a
...
...
@@ -19,8 +19,6 @@
#ifndef _LINUX_IF_EQL_H
#define _LINUX_IF_EQL_H
#include <linux/timer.h>
#define EQL_DEFAULT_SLAVE_PRIORITY 28800
#define EQL_DEFAULT_MAX_SLAVES 4
#define EQL_DEFAULT_MTU 576
...
...
@@ -35,32 +33,37 @@
#define EQL_GETMASTRCFG (SIOCDEVPRIVATE + 4)
#define EQL_SETMASTRCFG (SIOCDEVPRIVATE + 5)
#ifdef __KERNEL__
#include <linux/timer.h>
#include <linux/spinlock.h>
typedef
struct
slave
{
struct
list_head
list
;
struct
net_device
*
dev
;
long
priority
;
long
priority_bps
;
long
priority_Bps
;
long
bytes_queued
;
struct
slave
*
next
;
}
slave_t
;
typedef
struct
slave_queue
{
slave_t
*
head
;
slave_t
*
best_slave
;
spinlock_t
lock
;
struct
list_head
all_slaves
;
int
num_slaves
;
struct
net_device
*
master_dev
;
char
lock
;
}
slave_queue_t
;
typedef
struct
equalizer
{
slave_queue_t
*
queue
;
slave_queue_t
queue
;
int
min_slaves
;
int
max_slaves
;
struct
net_device_stats
*
stats
;
struct
net_device_stats
stats
;
struct
timer_list
timer
;
char
timer_on
;
}
equalizer_t
;
#endif
/* __KERNEL__ */
typedef
struct
master_config
{
char
master_name
[
16
];
int
max_slaves
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment