Merge tag 'clk-for-linus-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/clk...
[cascardo/linux.git] / include / net / request_sock.h
index 3fa4f82..fe41f3c 100644 (file)
@@ -39,8 +39,7 @@ struct request_sock_ops {
        void            (*send_reset)(struct sock *sk,
                                      struct sk_buff *skb);
        void            (*destructor)(struct request_sock *req);
-       void            (*syn_ack_timeout)(struct sock *sk,
-                                          struct request_sock *req);
+       void            (*syn_ack_timeout)(const struct request_sock *req);
 };
 
 int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req);
@@ -50,6 +49,7 @@ int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req);
 struct request_sock {
        struct sock_common              __req_common;
 #define rsk_refcnt                     __req_common.skc_refcnt
+#define rsk_hash                       __req_common.skc_hash
 
        struct request_sock             *dl_next;
        struct sock                     *rsk_listener;
@@ -61,7 +61,7 @@ struct request_sock {
        u32                             window_clamp; /* window clamp at creation time */
        u32                             rcv_wnd;          /* rcv_wnd offered first time */
        u32                             ts_recent;
-       unsigned long                   expires;
+       struct timer_list               rsk_timer;
        const struct request_sock_ops   *rsk_ops;
        struct sock                     *sk;
        u32                             secid;
@@ -91,6 +91,11 @@ static inline struct request_sock *inet_reqsk(struct sock *sk)
        return (struct request_sock *)sk;
 }
 
+static inline struct sock *req_to_sk(struct request_sock *req)
+{
+       return (struct sock *)req;
+}
+
 static inline void reqsk_free(struct request_sock *req)
 {
        /* temporary debugging */
@@ -104,9 +109,6 @@ static inline void reqsk_free(struct request_sock *req)
 
 static inline void reqsk_put(struct request_sock *req)
 {
-       /* temporary debugging, until req sock are put into ehash table */
-       WARN_ON_ONCE(atomic_read(&req->rsk_refcnt) != 1);
-
        if (atomic_dec_and_test(&req->rsk_refcnt))
                reqsk_free(req);
 }
@@ -118,12 +120,16 @@ extern int sysctl_max_syn_backlog;
  * @max_qlen_log - log_2 of maximal queued SYNs/REQUESTs
  */
 struct listen_sock {
-       u8                      max_qlen_log;
+       int                     qlen_inc; /* protected by listener lock */
+       int                     young_inc;/* protected by listener lock */
+
+       /* following fields can be updated by timer */
+       atomic_t                qlen_dec; /* qlen = qlen_inc - qlen_dec */
+       atomic_t                young_dec;
+
+       u8                      max_qlen_log ____cacheline_aligned_in_smp;
        u8                      synflood_warned;
        /* 2 bytes hole, try to use */
-       int                     qlen;
-       int                     qlen_young;
-       int                     clock_hand;
        u32                     hash_rnd;
        u32                     nr_table_entries;
        struct request_sock     *syn_table[0];
@@ -167,18 +173,11 @@ struct fastopen_queue {
  * %syn_wait_lock is necessary only to avoid proc interface having to grab the main
  * lock sock while browsing the listening hash (otherwise it's deadlock prone).
  *
- * This lock is acquired in read mode only from listening_get_next() seq_file
- * op and it's acquired in write mode _only_ from code that is actively
- * changing rskq_accept_head. All readers that are holding the master sock lock
- * don't need to grab this lock in read mode too as rskq_accept_head. writes
- * are always protected from the main sock lock.
  */
 struct request_sock_queue {
        struct request_sock     *rskq_accept_head;
        struct request_sock     *rskq_accept_tail;
-       rwlock_t                syn_wait_lock;
        u8                      rskq_defer_accept;
-       /* 3 bytes hole, try to pack */
        struct listen_sock      *listen_opt;
        struct fastopen_queue   *fastopenq; /* This is non-NULL iff TFO has been
                                             * enabled on this listener. Check
@@ -186,6 +185,9 @@ struct request_sock_queue {
                                             * to determine if TFO is enabled
                                             * right at this moment.
                                             */
+
+       /* temporary alignment, our goal is to get rid of this lock */
+       spinlock_t              syn_wait_lock ____cacheline_aligned_in_smp;
 };
 
 int reqsk_queue_alloc(struct request_sock_queue *queue,
@@ -211,12 +213,21 @@ static inline int reqsk_queue_empty(struct request_sock_queue *queue)
 }
 
 static inline void reqsk_queue_unlink(struct request_sock_queue *queue,
-                                     struct request_sock *req,
-                                     struct request_sock **prev_req)
+                                     struct request_sock *req)
 {
-       write_lock(&queue->syn_wait_lock);
-       *prev_req = req->dl_next;
-       write_unlock(&queue->syn_wait_lock);
+       struct listen_sock *lopt = queue->listen_opt;
+       struct request_sock **prev;
+
+       spin_lock(&queue->syn_wait_lock);
+
+       prev = &lopt->syn_table[req->rsk_hash];
+       while (*prev != req)
+               prev = &(*prev)->dl_next;
+       *prev = req->dl_next;
+
+       spin_unlock(&queue->syn_wait_lock);
+       if (del_timer(&req->rsk_timer))
+               reqsk_put(req);
 }
 
 static inline void reqsk_queue_add(struct request_sock_queue *queue,
@@ -249,63 +260,53 @@ static inline struct request_sock *reqsk_queue_remove(struct request_sock_queue
        return req;
 }
 
-static inline int reqsk_queue_removed(struct request_sock_queue *queue,
-                                     struct request_sock *req)
+static inline void reqsk_queue_removed(struct request_sock_queue *queue,
+                                      const struct request_sock *req)
 {
        struct listen_sock *lopt = queue->listen_opt;
 
        if (req->num_timeout == 0)
-               --lopt->qlen_young;
-
-       return --lopt->qlen;
+               atomic_inc(&lopt->young_dec);
+       atomic_inc(&lopt->qlen_dec);
 }
 
-static inline int reqsk_queue_added(struct request_sock_queue *queue)
+static inline void reqsk_queue_added(struct request_sock_queue *queue)
 {
        struct listen_sock *lopt = queue->listen_opt;
-       const int prev_qlen = lopt->qlen;
 
-       lopt->qlen_young++;
-       lopt->qlen++;
-       return prev_qlen;
+       lopt->young_inc++;
+       lopt->qlen_inc++;
 }
 
-static inline int reqsk_queue_len(const struct request_sock_queue *queue)
+static inline int listen_sock_qlen(const struct listen_sock *lopt)
 {
-       return queue->listen_opt != NULL ? queue->listen_opt->qlen : 0;
+       return lopt->qlen_inc - atomic_read(&lopt->qlen_dec);
 }
 
-static inline int reqsk_queue_len_young(const struct request_sock_queue *queue)
+static inline int listen_sock_young(const struct listen_sock *lopt)
 {
-       return queue->listen_opt->qlen_young;
+       return lopt->young_inc - atomic_read(&lopt->young_dec);
 }
 
-static inline int reqsk_queue_is_full(const struct request_sock_queue *queue)
+static inline int reqsk_queue_len(const struct request_sock_queue *queue)
 {
-       return queue->listen_opt->qlen >> queue->listen_opt->max_qlen_log;
+       const struct listen_sock *lopt = queue->listen_opt;
+
+       return lopt ? listen_sock_qlen(lopt) : 0;
 }
 
-static inline void reqsk_queue_hash_req(struct request_sock_queue *queue,
-                                       u32 hash, struct request_sock *req,
-                                       unsigned long timeout)
+static inline int reqsk_queue_len_young(const struct request_sock_queue *queue)
 {
-       struct listen_sock *lopt = queue->listen_opt;
+       return listen_sock_young(queue->listen_opt);
+}
 
-       req->expires = jiffies + timeout;
-       req->num_retrans = 0;
-       req->num_timeout = 0;
-       req->sk = NULL;
-       req->dl_next = lopt->syn_table[hash];
-
-       /* before letting lookups find us, make sure all req fields
-        * are committed to memory and refcnt initialized.
-        */
-       smp_wmb();
-       atomic_set(&req->rsk_refcnt, 1);
-
-       write_lock(&queue->syn_wait_lock);
-       lopt->syn_table[hash] = req;
-       write_unlock(&queue->syn_wait_lock);
+static inline int reqsk_queue_is_full(const struct request_sock_queue *queue)
+{
+       return reqsk_queue_len(queue) >> queue->listen_opt->max_qlen_log;
 }
 
+void reqsk_queue_hash_req(struct request_sock_queue *queue,
+                         u32 hash, struct request_sock *req,
+                         unsigned long timeout);
+
 #endif /* _REQUEST_SOCK_H */