Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fs/nfsd/nfs3proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
struct nfsd3_readres *resp = rqstp->rq_resp;
u32 max_blocksize = svc_max_payload(rqstp);
unsigned long cnt = min(argp->count, max_blocksize);
cnt = min(cnt, (unsigned long)rqstp->rq_res.buflen);

dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
SVCFH_fmt(&argp->fh),
Expand Down
1 change: 1 addition & 0 deletions fs/nfsd/nfsproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ nfsd_proc_read(struct svc_rqst *rqstp)
argp->count);
argp->count = NFSSVC_MAXBLKSIZE_V2;
}
argp->count = min_t(u32, argp->count, rqstp->rq_res.buflen);
svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);

resp->count = argp->count;
Expand Down
23 changes: 17 additions & 6 deletions include/net/af_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,6 @@ struct unix_skb_parms {

#define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb))

#define unix_state_lock(s) spin_lock(&unix_sk(s)->lock)
#define unix_state_unlock(s) spin_unlock(&unix_sk(s)->lock)
#define unix_state_lock_nested(s) \
spin_lock_nested(&unix_sk(s)->lock, \
SINGLE_DEPTH_NESTING)

/* The AF_UNIX socket */
struct unix_sock {
/* WARNING: sk has to be the first member */
Expand All @@ -72,6 +66,23 @@ static inline struct unix_sock *unix_sk(const struct sock *sk)
return (struct unix_sock *)sk;
}

#define unix_state_lock(s) spin_lock(&unix_sk(s)->lock)
#define unix_state_unlock(s) spin_unlock(&unix_sk(s)->lock)
enum unix_socket_lock_class {
U_LOCK_NORMAL,
U_LOCK_SECOND, /* for double locking, see unix_state_double_lock(). */
U_LOCK_DIAG, /* used while dumping icons, see sk_diag_dump_icons(). */
U_LOCK_GC_LISTENER, /* used for listening socket while determining gc
* candidates to close a small race window.
*/
};

static inline void unix_state_lock_nested(struct sock *sk,
enum unix_socket_lock_class subclass)
{
spin_lock_nested(&unix_sk(sk)->lock, subclass);
}

#define peer_wait peer_wq.wait

long unix_inq_len(struct sock *sk);
Expand Down
16 changes: 6 additions & 10 deletions net/tls/tls_sw.c
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,6 @@ static void tls_encrypt_done(struct crypto_async_request *req, int err)
struct scatterlist *sge;
struct sk_msg *msg_en;
struct tls_rec *rec;
bool ready = false;
int pending;

rec = container_of(aead_req, struct tls_rec, aead_req);
Expand Down Expand Up @@ -475,8 +474,12 @@ static void tls_encrypt_done(struct crypto_async_request *req, int err)
/* If received record is at head of tx_list, schedule tx */
first_rec = list_first_entry(&ctx->tx_list,
struct tls_rec, list);
if (rec == first_rec)
ready = true;
if (rec == first_rec) {
/* Schedule the transmission */
if (!test_and_set_bit(BIT_TX_SCHEDULED,
&ctx->tx_bitmask))
schedule_delayed_work(&ctx->tx_work.work, 1);
}
}

spin_lock_bh(&ctx->encrypt_compl_lock);
Expand All @@ -485,13 +488,6 @@ static void tls_encrypt_done(struct crypto_async_request *req, int err)
if (!pending && ctx->async_notify)
complete(&ctx->async_wait.completion);
spin_unlock_bh(&ctx->encrypt_compl_lock);

if (!ready)
return;

/* Schedule the transmission */
if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask))
schedule_delayed_work(&ctx->tx_work.work, 1);
}

static int tls_do_encryption(struct sock *sk,
Expand Down
14 changes: 6 additions & 8 deletions net/unix/af_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -1115,13 +1115,11 @@ static void unix_state_double_lock(struct sock *sk1, struct sock *sk2)
unix_state_lock(sk1);
return;
}
if (sk1 < sk2) {
unix_state_lock(sk1);
unix_state_lock_nested(sk2);
} else {
unix_state_lock(sk2);
unix_state_lock_nested(sk1);
}
if (sk1 > sk2)
swap(sk1, sk2);

unix_state_lock(sk1);
unix_state_lock_nested(sk2, U_LOCK_SECOND);
}

static void unix_state_double_unlock(struct sock *sk1, struct sock *sk2)
Expand Down Expand Up @@ -1343,7 +1341,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
goto out_unlock;
}

unix_state_lock_nested(sk);
unix_state_lock_nested(sk, U_LOCK_SECOND);

if (sk->sk_state != st) {
unix_state_unlock(sk);
Expand Down
2 changes: 1 addition & 1 deletion net/unix/diag.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ static int sk_diag_dump_icons(struct sock *sk, struct sk_buff *nlskb)
* queue lock. With the other's queue locked it's
* OK to lock the state.
*/
unix_state_lock_nested(req);
unix_state_lock_nested(req, U_LOCK_DIAG);
peer = unix_sk(req)->peer;
buf[i++] = (peer ? sock_i_ino(peer) : 0);
unix_state_unlock(req);
Expand Down
18 changes: 17 additions & 1 deletion net/unix/garbage.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,12 +233,23 @@ void unix_gc(void)
* receive queues. Other, non candidate sockets _can_ be
* added to queue, so we must make sure only to touch
* candidates.
*
* Embryos, though never candidates themselves, affect which
* candidates are reachable by the garbage collector. Before
* being added to a listener's queue, an embryo may already
* receive data carrying SCM_RIGHTS, potentially making the
* passed socket a candidate that is not yet reachable by the
* collector. It becomes reachable once the embryo is
* enqueued. Therefore, we must ensure that no SCM-laden
* embryo appears in a (candidate) listener's queue between
* consecutive scan_children() calls.
*/
list_for_each_entry_safe(u, next, &gc_inflight_list, link) {
struct sock *sk = &u->sk;
long total_refs;
long inflight_refs;

total_refs = file_count(u->sk.sk_socket->file);
total_refs = file_count(sk->sk_socket->file);
inflight_refs = atomic_long_read(&u->inflight);

BUG_ON(inflight_refs < 1);
Expand All @@ -247,6 +258,11 @@ void unix_gc(void)
list_move_tail(&u->link, &gc_candidates);
__set_bit(UNIX_GC_CANDIDATE, &u->gc_flags);
__set_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags);

if (sk->sk_state == TCP_LISTEN) {
unix_state_lock_nested(sk, U_LOCK_GC_LISTENER);
unix_state_unlock(sk);
}
}
}

Expand Down
Loading