From fb109f282c5206d834ac8a054902b60d1b7627c5 Mon Sep 17 00:00:00 2001
From: Stefano Ceccherini <stefano.ceccherini@gmail.com>
Date: Sat, 23 Aug 2014 18:23:38 +0200
Subject: [PATCH] netstack: Interface: Improve locking. Don't acquire the
interface lock in ::_SetUp() and SetDown() before calling the lower layers.
Grab the all interfaces lock before setting the interface busy. Mark the
interface busy instead, using the newly added SetBusy() method. In
get_interface() and SetDown(): check if the interface is busy.
---
src/add-ons/kernel/network/stack/interfaces.cpp | 33 ++++++++++++++++---------
src/add-ons/kernel/network/stack/interfaces.h | 4 +++
2 files changed, 25 insertions(+), 12 deletions(-)
diff --git a/src/add-ons/kernel/network/stack/interfaces.cpp b/src/add-ons/kernel/network/stack/interfaces.cpp
index 20b4110..0c08286 100644
a
|
b
|
Interface::SetDown()
|
933 | 933 | if ((flags & IFF_UP) == 0) |
934 | 934 | return; |
935 | 935 | |
936 | | // TODO: We acquire also the net_interfaces lock here |
937 | | // to avoid a lock inversion in the ipv6 protocol implementation |
938 | | // (see ticket #9377). |
939 | | // A better solution would be to avoid locking the interface lock (fLock) |
940 | | // when calling the lower layers. |
941 | | RecursiveLocker interfacesLocker(sLock); |
942 | | RecursiveLocker locker(fLock); |
| 936 | if (IsBusy()) |
| 937 | return; |
| 938 | |
| 939 | RecursiveLocker interfacesLock(sLock); |
| 940 | SetBusy(true); |
| 941 | interfacesLock.Unlock(); |
943 | 942 | |
944 | 943 | DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator(); |
945 | 944 | while (domain_datalink* datalink = iterator.Next()) { |
… |
… |
Interface::SetDown()
|
947 | 946 | } |
948 | 947 | |
949 | 948 | flags &= ~IFF_UP; |
| 949 | |
| 950 | SetBusy(false); |
950 | 951 | } |
951 | 952 | |
952 | 953 | |
… |
… |
Interface::_SetUp()
|
1076 | 1077 | if (status != B_OK) |
1077 | 1078 | return status; |
1078 | 1079 | |
1079 | | // Propagate flag to all datalink protocols |
1080 | | |
1081 | | RecursiveLocker locker(fLock); |
| 1080 | RecursiveLocker interfacesLocker(sLock); |
| 1081 | SetBusy(true); |
| 1082 | interfacesLocker.Unlock(); |
1082 | 1083 | |
| 1084 | // Propagate flag to all datalink protocols |
1083 | 1085 | DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator(); |
1084 | 1086 | while (domain_datalink* datalink = iterator.Next()) { |
1085 | 1087 | status = datalink->first_info->interface_up(datalink->first_protocol); |
… |
… |
Interface::_SetUp()
|
1097 | 1099 | } |
1098 | 1100 | |
1099 | 1101 | down_device_interface(fDeviceInterface); |
| 1102 | SetBusy(false); |
1100 | 1103 | return status; |
1101 | 1104 | } |
1102 | 1105 | } |
… |
… |
Interface::_SetUp()
|
1109 | 1112 | } |
1110 | 1113 | |
1111 | 1114 | flags |= IFF_UP; |
| 1115 | SetBusy(false); |
| 1116 | |
1112 | 1117 | return B_OK; |
1113 | 1118 | } |
1114 | 1119 | |
… |
… |
get_interface(net_domain* domain, uint32 index)
|
1409 | 1414 | interface = sInterfaces.First(); |
1410 | 1415 | else |
1411 | 1416 | interface = find_interface(index); |
1412 | | if (interface == NULL) |
| 1417 | if (interface == NULL || interface->IsBusy()) |
1413 | 1418 | return NULL; |
1414 | 1419 | |
1415 | 1420 | if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK) |
… |
… |
get_interface(net_domain* domain, const char* name)
|
1426 | 1431 | RecursiveLocker locker(sLock); |
1427 | 1432 | |
1428 | 1433 | Interface* interface = find_interface(name); |
1429 | | if (interface == NULL) |
| 1434 | if (interface == NULL || interface->IsBusy()) |
1430 | 1435 | return NULL; |
1431 | 1436 | |
1432 | 1437 | if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK) |
… |
… |
get_interface_for_device(net_domain* domain, uint32 index)
|
1445 | 1450 | InterfaceList::Iterator iterator = sInterfaces.GetIterator(); |
1446 | 1451 | while (Interface* interface = iterator.Next()) { |
1447 | 1452 | if (interface->device->index == index) { |
| 1453 | if (interface->IsBusy()) |
| 1454 | return NULL; |
1448 | 1455 | if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK) |
1449 | 1456 | return NULL; |
1450 | 1457 | |
… |
… |
get_interface_for_link(net_domain* domain, const sockaddr* _linkAddress)
|
1479 | 1486 | && !strcmp(interface->name, (const char*)linkAddress.sdl_data)) |
1480 | 1487 | || (linkAddress.sdl_nlen == 0 && linkAddress.sdl_alen == 0 |
1481 | 1488 | && linkAddress.sdl_index == interface->index)) { |
| 1489 | if (interface->IsBusy()) |
| 1490 | return NULL; |
1482 | 1491 | if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK) |
1483 | 1492 | return NULL; |
1484 | 1493 | |
diff --git a/src/add-ons/kernel/network/stack/interfaces.h b/src/add-ons/kernel/network/stack/interfaces.h
index f7bc63b..9c0cb63 100644
a
|
b
|
public:
|
152 | 152 | domain_datalink* DomainDatalink(net_domain* domain) |
153 | 153 | { return DomainDatalink(domain->family); } |
154 | 154 | |
| 155 | inline void SetBusy(bool busy) { atomic_set(&fBusy, busy ? 1 : 0); }; |
| 156 | inline bool IsBusy() const { return atomic_get((int32*)&fBusy) == 1 ;}; |
| 157 | |
155 | 158 | #if ENABLE_DEBUGGER_COMMANDS |
156 | 159 | void Dump() const; |
157 | 160 | #endif |
… |
… |
private:
|
166 | 169 | |
167 | 170 | private: |
168 | 171 | recursive_lock fLock; |
| 172 | int32 fBusy; |
169 | 173 | net_device_interface* fDeviceInterface; |
170 | 174 | AddressList fAddresses; |
171 | 175 | DatalinkTable fDatalinkTable; |