Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/in_pcb.h
Show First 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
#include <sys/_mutex.h> | #include <sys/_mutex.h> | ||||
#include <sys/_rwlock.h> | #include <sys/_rwlock.h> | ||||
#include <net/route.h> | #include <net/route.h> | ||||
#ifdef _KERNEL | #ifdef _KERNEL | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/rwlock.h> | #include <sys/rwlock.h> | ||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <net/if.h> | |||||
#include <net/if_var.h> | |||||
#include <vm/uma.h> | #include <vm/uma.h> | ||||
#endif | #endif | ||||
#include <sys/ck.h> | |||||
#define in6pcb inpcb /* for KAME src sync over BSD*'s */ | #define in6pcb inpcb /* for KAME src sync over BSD*'s */ | ||||
#define in6p_sp inp_sp /* for KAME src sync over BSD*'s */ | #define in6p_sp inp_sp /* for KAME src sync over BSD*'s */ | ||||
/* | /* | ||||
* struct inpcb is the common protocol control block structure used in most | * struct inpcb is the common protocol control block structure used in most | ||||
* IP transport protocols. | * IP transport protocols. | ||||
* | * | ||||
* Pointers to local and foreign host table entries, local and foreign socket | * Pointers to local and foreign host table entries, local and foreign socket | ||||
* numbers, and pointers up (to a socket structure) and down (to a | * numbers, and pointers up (to a socket structure) and down (to a | ||||
* protocol-specific control block) are stored here. | * protocol-specific control block) are stored here. | ||||
*/ | */ | ||||
LIST_HEAD(inpcbhead, inpcb); | CK_LIST_HEAD(inpcbhead, inpcb); | ||||
LIST_HEAD(inpcbporthead, inpcbport); | CK_LIST_HEAD(inpcbporthead, inpcbport); | ||||
typedef uint64_t inp_gen_t; | typedef uint64_t inp_gen_t; | ||||
/* | /* | ||||
* PCB with AF_INET6 null bind'ed laddr can receive AF_INET input packet. | * PCB with AF_INET6 null bind'ed laddr can receive AF_INET input packet. | ||||
* So, AF_INET6 null laddr is also used as AF_INET null laddr, by utilizing | * So, AF_INET6 null laddr is also used as AF_INET null laddr, by utilizing | ||||
* the following structure. | * the following structure. | ||||
*/ | */ | ||||
struct in_addr_4in6 { | struct in_addr_4in6 { | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | |||||
* read-lock usage during modification, this model can be applied to other | * read-lock usage during modification, this model can be applied to other | ||||
* protocols (especially SCTP). | * protocols (especially SCTP). | ||||
*/ | */ | ||||
struct icmp6_filter; | struct icmp6_filter; | ||||
struct inpcbpolicy; | struct inpcbpolicy; | ||||
struct m_snd_tag; | struct m_snd_tag; | ||||
struct inpcb { | struct inpcb { | ||||
/* Cache line #1 (amd64) */ | /* Cache line #1 (amd64) */ | ||||
LIST_ENTRY(inpcb) inp_hash; /* (h/i) hash list */ | CK_LIST_ENTRY(inpcb) inp_hash; /* (h/i) hash list */ | ||||
LIST_ENTRY(inpcb) inp_pcbgrouphash; /* (g/i) hash list */ | CK_LIST_ENTRY(inpcb) inp_pcbgrouphash; /* (g/i) hash list */ | ||||
struct rwlock inp_lock; | struct rwlock inp_lock; | ||||
/* Cache line #2 (amd64) */ | /* Cache line #2 (amd64) */ | ||||
#define inp_start_zero inp_hpts | #define inp_start_zero inp_hpts | ||||
#define inp_zero_size (sizeof(struct inpcb) - \ | #define inp_zero_size (sizeof(struct inpcb) - \ | ||||
offsetof(struct inpcb, inp_start_zero)) | offsetof(struct inpcb, inp_start_zero)) | ||||
TAILQ_ENTRY(inpcb) inp_hpts; /* pacing out queue next lock(b) */ | TAILQ_ENTRY(inpcb) inp_hpts; /* pacing out queue next lock(b) */ | ||||
uint32_t inp_hpts_request; /* Current hpts request, zero if | uint32_t inp_hpts_request; /* Current hpts request, zero if | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | struct { | ||||
/* (i) IP multicast options */ | /* (i) IP multicast options */ | ||||
struct ip6_moptions *in6p_moptions; | struct ip6_moptions *in6p_moptions; | ||||
/* (i) ICMPv6 code type filter */ | /* (i) ICMPv6 code type filter */ | ||||
struct icmp6_filter *in6p_icmp6filt; | struct icmp6_filter *in6p_icmp6filt; | ||||
/* (i) IPV6_CHECKSUM setsockopt */ | /* (i) IPV6_CHECKSUM setsockopt */ | ||||
int in6p_cksum; | int in6p_cksum; | ||||
short in6p_hops; | short in6p_hops; | ||||
}; | }; | ||||
LIST_ENTRY(inpcb) inp_portlist; /* (i/h) */ | CK_LIST_ENTRY(inpcb) inp_portlist; /* (i/h) */ | ||||
struct inpcbport *inp_phd; /* (i/h) head of this list */ | struct inpcbport *inp_phd; /* (i/h) head of this list */ | ||||
inp_gen_t inp_gencnt; /* (c) generation count */ | inp_gen_t inp_gencnt; /* (c) generation count */ | ||||
struct llentry *inp_lle; /* cached L2 information */ | struct llentry *inp_lle; /* cached L2 information */ | ||||
rt_gen_t inp_rt_cookie; /* generation for route entry */ | rt_gen_t inp_rt_cookie; /* generation for route entry */ | ||||
union { /* cached L3 information */ | union { /* cached L3 information */ | ||||
struct route inp_route; | struct route inp_route; | ||||
struct route_in6 inp_route6; | struct route_in6 inp_route6; | ||||
}; | }; | ||||
LIST_ENTRY(inpcb) inp_list; /* (p/l) list for all PCBs for proto */ | CK_LIST_ENTRY(inpcb) inp_list; /* (p/l) list for all PCBs for proto */ | ||||
jtl: While here, please update/fix the locking annotations on these lines. (For example, the [w] and… | |||||
/* (p[w]) for list iteration */ | /* (p[w]) for list iteration */ | ||||
/* (p[r]/l) for addition/removal */ | /* (p[r]/l) for addition/removal */ | ||||
struct epoch_context inp_epoch_ctx; | |||||
}; | }; | ||||
#endif /* _KERNEL */ | #endif /* _KERNEL */ | ||||
#define inp_fport inp_inc.inc_fport | #define inp_fport inp_inc.inc_fport | ||||
#define inp_lport inp_inc.inc_lport | #define inp_lport inp_inc.inc_lport | ||||
#define inp_faddr inp_inc.inc_faddr | #define inp_faddr inp_inc.inc_faddr | ||||
#define inp_laddr inp_inc.inc_laddr | #define inp_laddr inp_inc.inc_laddr | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | struct xinpgen { | ||||
so_gen_t xig_sogen; /* socket generation count this time */ | so_gen_t xig_sogen; /* socket generation count this time */ | ||||
} __aligned(8); | } __aligned(8); | ||||
#ifdef _KERNEL | #ifdef _KERNEL | ||||
void in_pcbtoxinpcb(const struct inpcb *, struct xinpcb *); | void in_pcbtoxinpcb(const struct inpcb *, struct xinpcb *); | ||||
#endif | #endif | ||||
#endif /* _SYS_SOCKETVAR_H_ */ | #endif /* _SYS_SOCKETVAR_H_ */ | ||||
struct inpcbport { | struct inpcbport { | ||||
LIST_ENTRY(inpcbport) phd_hash; | struct epoch_context phd_epoch_ctx; | ||||
CK_LIST_ENTRY(inpcbport) phd_hash; | |||||
struct inpcbhead phd_pcblist; | struct inpcbhead phd_pcblist; | ||||
u_short phd_port; | u_short phd_port; | ||||
}; | }; | ||||
struct in_pcblist { | struct in_pcblist { | ||||
int il_count; | int il_count; | ||||
struct epoch_context il_epoch_ctx; | struct epoch_context il_epoch_ctx; | ||||
struct inpcbinfo *il_pcbinfo; | struct inpcbinfo *il_pcbinfo; | ||||
Show All 24 Lines | |||||
* (g) Locked by ipi_lock | * (g) Locked by ipi_lock | ||||
* (l) Locked by ipi_list_lock | * (l) Locked by ipi_list_lock | ||||
* (h) Read using either ipi_hash_lock or inpcb lock; write requires both | * (h) Read using either ipi_hash_lock or inpcb lock; write requires both | ||||
* (p) Protected by one or more pcbgroup locks | * (p) Protected by one or more pcbgroup locks | ||||
* (x) Synchronisation properties poorly defined | * (x) Synchronisation properties poorly defined | ||||
*/ | */ | ||||
struct inpcbinfo { | struct inpcbinfo { | ||||
/* | /* | ||||
* Global lock protecting full inpcb list traversal | * Global lock protecting full inpcb list traversal | ||||
Not Done Inline ActionsIts not really "inpcb modification", but rather "inpcb list modification", right? jtl: Its not really "inpcb modification", but rather "inpcb list modification", right? | |||||
Not Done Inline ActionsCorrect. mmacy: Correct. | |||||
Not Done Inline ActionsOK. Then, it seems like this commend should be updated when you commit the change. jtl: OK. Then, it seems like this commend should be updated when you commit the change. | |||||
*/ | */ | ||||
struct rwlock ipi_lock; | struct rwlock ipi_lock; | ||||
/* | /* | ||||
* Global list of inpcbs on the protocol. | * Global list of inpcbs on the protocol. | ||||
*/ | */ | ||||
struct inpcbhead *ipi_listhead; /* (g/l) */ | struct inpcbhead *ipi_listhead; /* (g/l) */ | ||||
u_int ipi_count; /* (l) */ | u_int ipi_count; /* (l) */ | ||||
▲ Show 20 Lines • Show All 167 Lines • ▼ Show 20 Lines | void inp_4tuple_get(struct inpcb *inp, uint32_t *laddr, uint16_t *lp, | ||||
uint32_t *faddr, uint16_t *fp); | uint32_t *faddr, uint16_t *fp); | ||||
int inp_so_options(const struct inpcb *inp); | int inp_so_options(const struct inpcb *inp); | ||||
#endif /* _KERNEL */ | #endif /* _KERNEL */ | ||||
#define INP_INFO_LOCK_INIT(ipi, d) \ | #define INP_INFO_LOCK_INIT(ipi, d) \ | ||||
rw_init_flags(&(ipi)->ipi_lock, (d), RW_RECURSE) | rw_init_flags(&(ipi)->ipi_lock, (d), RW_RECURSE) | ||||
#define INP_INFO_LOCK_DESTROY(ipi) rw_destroy(&(ipi)->ipi_lock) | #define INP_INFO_LOCK_DESTROY(ipi) rw_destroy(&(ipi)->ipi_lock) | ||||
#define INP_INFO_RLOCK(ipi) rw_rlock(&(ipi)->ipi_lock) | #define INP_INFO_RLOCK(ipi) NET_EPOCH_ENTER() | ||||
#define INP_INFO_WLOCK(ipi) rw_wlock(&(ipi)->ipi_lock) | #define INP_INFO_WLOCK(ipi) rw_wlock(&(ipi)->ipi_lock) | ||||
#define INP_INFO_TRY_RLOCK(ipi) rw_try_rlock(&(ipi)->ipi_lock) | #define INP_INFO_TRY_RLOCK(ipi) ({NET_EPOCH_ENTER(); 1;}) | ||||
#define INP_INFO_TRY_WLOCK(ipi) rw_try_wlock(&(ipi)->ipi_lock) | #define INP_INFO_TRY_WLOCK(ipi) rw_try_wlock(&(ipi)->ipi_lock) | ||||
#define INP_INFO_TRY_UPGRADE(ipi) rw_try_upgrade(&(ipi)->ipi_lock) | #define INP_INFO_TRY_UPGRADE(ipi) rw_try_upgrade(&(ipi)->ipi_lock) | ||||
jtlUnsubmitted Not Done Inline ActionsJust off the top of my head, this section of lock macros doesn't look right. For example, INP_INFO_TRY_UPGRADE can't try to upgrade an rw lock that it won't actually own in read mode (since INP_INFO_RLOCK doesn't actually acquire a read lock). Also, now that we will only hold a lock when writing, it seems like this should all switch from rw locks to mutexes. jtl: Just off the top of my head, this section of lock macros doesn't look right.
For example… | |||||
#define INP_INFO_WLOCKED(ipi) rw_wowned(&(ipi)->ipi_lock) | #define INP_INFO_WLOCKED(ipi) rw_wowned(&(ipi)->ipi_lock) | ||||
#define INP_INFO_RUNLOCK(ipi) rw_runlock(&(ipi)->ipi_lock) | #define INP_INFO_RUNLOCK(ipi) NET_EPOCH_EXIT() | ||||
#define INP_INFO_WUNLOCK(ipi) rw_wunlock(&(ipi)->ipi_lock) | #define INP_INFO_WUNLOCK(ipi) rw_wunlock(&(ipi)->ipi_lock) | ||||
#define INP_INFO_LOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_lock, RA_LOCKED) | #define INP_INFO_LOCK_ASSERT(ipi) MPASS(in_epoch() || rw_wowned(&(ipi)->ipi_lock)) | ||||
#define INP_INFO_RLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_lock, RA_RLOCKED) | #define INP_INFO_RLOCK_ASSERT(ipi) MPASS(in_epoch()) | ||||
#define INP_INFO_WLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_lock, RA_WLOCKED) | #define INP_INFO_WLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_lock, RA_WLOCKED) | ||||
#define INP_INFO_UNLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_lock, RA_UNLOCKED) | #define INP_INFO_UNLOCK_ASSERT(ipi) MPASS(!in_epoch() && !rw_wowned(&(ipi)->ipi_lock)) | ||||
#define INP_LIST_LOCK_INIT(ipi, d) \ | #define INP_LIST_LOCK_INIT(ipi, d) \ | ||||
jtlUnsubmitted Not Done Inline ActionsDo the INP_LIST macros need similar treatment to the INP_INFO macros? jtl: Do the INP_LIST macros need similar treatment to the INP_INFO macros? | |||||
mmacyAuthorUnsubmitted Not Done Inline ActionsNo, I'm keeping them unchanged. I don't think that the code it protects is performance critical. mmacy: No, I'm keeping them unchanged. I don't think that the code it protects is performance critical. | |||||
rw_init_flags(&(ipi)->ipi_list_lock, (d), 0) | rw_init_flags(&(ipi)->ipi_list_lock, (d), 0) | ||||
#define INP_LIST_LOCK_DESTROY(ipi) rw_destroy(&(ipi)->ipi_list_lock) | #define INP_LIST_LOCK_DESTROY(ipi) rw_destroy(&(ipi)->ipi_list_lock) | ||||
#define INP_LIST_RLOCK(ipi) rw_rlock(&(ipi)->ipi_list_lock) | #define INP_LIST_RLOCK(ipi) rw_rlock(&(ipi)->ipi_list_lock) | ||||
#define INP_LIST_WLOCK(ipi) rw_wlock(&(ipi)->ipi_list_lock) | #define INP_LIST_WLOCK(ipi) rw_wlock(&(ipi)->ipi_list_lock) | ||||
#define INP_LIST_TRY_RLOCK(ipi) rw_try_rlock(&(ipi)->ipi_list_lock) | #define INP_LIST_TRY_RLOCK(ipi) rw_try_rlock(&(ipi)->ipi_list_lock) | ||||
#define INP_LIST_TRY_WLOCK(ipi) rw_try_wlock(&(ipi)->ipi_list_lock) | #define INP_LIST_TRY_WLOCK(ipi) rw_try_wlock(&(ipi)->ipi_list_lock) | ||||
#define INP_LIST_TRY_UPGRADE(ipi) rw_try_upgrade(&(ipi)->ipi_list_lock) | #define INP_LIST_TRY_UPGRADE(ipi) rw_try_upgrade(&(ipi)->ipi_list_lock) | ||||
#define INP_LIST_RUNLOCK(ipi) rw_runlock(&(ipi)->ipi_list_lock) | #define INP_LIST_RUNLOCK(ipi) rw_runlock(&(ipi)->ipi_list_lock) | ||||
#define INP_LIST_WUNLOCK(ipi) rw_wunlock(&(ipi)->ipi_list_lock) | #define INP_LIST_WUNLOCK(ipi) rw_wunlock(&(ipi)->ipi_list_lock) | ||||
#define INP_LIST_LOCK_ASSERT(ipi) \ | #define INP_LIST_LOCK_ASSERT(ipi) \ | ||||
rw_assert(&(ipi)->ipi_list_lock, RA_LOCKED) | rw_assert(&(ipi)->ipi_list_lock, RA_LOCKED) | ||||
#define INP_LIST_RLOCK_ASSERT(ipi) \ | #define INP_LIST_RLOCK_ASSERT(ipi) \ | ||||
rw_assert(&(ipi)->ipi_list_lock, RA_RLOCKED) | rw_assert(&(ipi)->ipi_list_lock, RA_RLOCKED) | ||||
#define INP_LIST_WLOCK_ASSERT(ipi) \ | #define INP_LIST_WLOCK_ASSERT(ipi) \ | ||||
rw_assert(&(ipi)->ipi_list_lock, RA_WLOCKED) | rw_assert(&(ipi)->ipi_list_lock, RA_WLOCKED) | ||||
#define INP_LIST_UNLOCK_ASSERT(ipi) \ | #define INP_LIST_UNLOCK_ASSERT(ipi) \ | ||||
rw_assert(&(ipi)->ipi_list_lock, RA_UNLOCKED) | rw_assert(&(ipi)->ipi_list_lock, RA_UNLOCKED) | ||||
#define INP_HASH_LOCK_INIT(ipi, d) \ | #define INP_HASH_LOCK_INIT(ipi, d) \ | ||||
rw_init_flags(&(ipi)->ipi_hash_lock, (d), 0) | rw_init_flags(&(ipi)->ipi_hash_lock, (d), 0) | ||||
#define INP_HASH_LOCK_DESTROY(ipi) rw_destroy(&(ipi)->ipi_hash_lock) | #define INP_HASH_LOCK_DESTROY(ipi) rw_destroy(&(ipi)->ipi_hash_lock) | ||||
#define INP_HASH_RLOCK(ipi) rw_rlock(&(ipi)->ipi_hash_lock) | #define INP_HASH_RLOCK(ipi) NET_EPOCH_ENTER() | ||||
#define INP_HASH_WLOCK(ipi) rw_wlock(&(ipi)->ipi_hash_lock) | #define INP_HASH_WLOCK(ipi) rw_wlock(&(ipi)->ipi_hash_lock) | ||||
#define INP_HASH_RUNLOCK(ipi) rw_runlock(&(ipi)->ipi_hash_lock) | #define INP_HASH_RUNLOCK(ipi) NET_EPOCH_EXIT() | ||||
#define INP_HASH_WUNLOCK(ipi) rw_wunlock(&(ipi)->ipi_hash_lock) | #define INP_HASH_WUNLOCK(ipi) rw_wunlock(&(ipi)->ipi_hash_lock) | ||||
#define INP_HASH_LOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_hash_lock, \ | #define INP_HASH_LOCK_ASSERT(ipi) MPASS(in_epoch() || rw_wowned(&(ipi)->ipi_hash_lock)) | ||||
RA_LOCKED) | |||||
#define INP_HASH_WLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_hash_lock, \ | #define INP_HASH_WLOCK_ASSERT(ipi) rw_assert(&(ipi)->ipi_hash_lock, \ | ||||
RA_WLOCKED) | RA_WLOCKED) | ||||
#define INP_GROUP_LOCK_INIT(ipg, d) mtx_init(&(ipg)->ipg_lock, (d), NULL, \ | #define INP_GROUP_LOCK_INIT(ipg, d) mtx_init(&(ipg)->ipg_lock, (d), NULL, \ | ||||
MTX_DEF | MTX_DUPOK) | MTX_DEF | MTX_DUPOK) | ||||
#define INP_GROUP_LOCK_DESTROY(ipg) mtx_destroy(&(ipg)->ipg_lock) | #define INP_GROUP_LOCK_DESTROY(ipg) mtx_destroy(&(ipg)->ipg_lock) | ||||
#define INP_GROUP_LOCK(ipg) mtx_lock(&(ipg)->ipg_lock) | #define INP_GROUP_LOCK(ipg) mtx_lock(&(ipg)->ipg_lock) | ||||
▲ Show 20 Lines • Show All 213 Lines • Show Last 20 Lines |
While here, please update/fix the locking annotations on these lines. (For example, the [w] and [r] are clearly backwards.)