blob: 096eb9d184913e7b9a164ef45a07b38045ab5c90 [file] [log] [blame]
/*
* vim:noexpandtab:shiftwidth=8:tabstop=8:
*
* Copyright (C) 2012, The Linux Box Corporation
* Contributor : Matt Benjamin <matt@linuxbox.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* -------------
*/
/**
* @file nfs_req_queue.h
* @author Matt Benjamin <matt@linuxbox.com>
* @brief NFS request queue package
*
* This module defines an infrastructure for classification and
* dispatch of incoming protocol requests using a forward queueing
* model, with priority and isolation partitions.
*/
#ifndef NFS_REQ_QUEUE_H
#define NFS_REQ_QUEUE_H
#include "gsh_list.h"
#include "wait_queue.h"
struct req_q {
pthread_spinlock_t sp;
struct glist_head q; /* LIFO */
uint32_t size;
uint32_t max;
uint32_t waiters;
};
struct req_q_pair {
const char *s;
GSH_CACHE_PAD(0);
struct req_q producer; /* from decoder */
GSH_CACHE_PAD(1);
struct req_q consumer; /* to executor */
GSH_CACHE_PAD(2);
};
#define REQ_Q_MOUNT 0
#define REQ_Q_CALL 1
#define REQ_Q_LOW_LATENCY 2 /*< GETATTR, RENEW, etc */
#define REQ_Q_HIGH_LATENCY 3 /*< READ, WRITE, COMMIT, etc */
#define N_REQ_QUEUES 4
extern const char *req_q_s[N_REQ_QUEUES]; /* for debug prints */
struct req_q_set {
struct req_q_pair qset[N_REQ_QUEUES];
};
struct nfs_req_st {
struct {
uint32_t ctr;
struct req_q_set nfs_request_q;
uint64_t size;
pthread_spinlock_t sp;
struct glist_head wait_list;
uint32_t waiters;
} reqs;
GSH_CACHE_PAD(1);
struct {
pthread_mutex_t mtx;
struct glist_head q;
uint32_t stalled;
bool active;
} stallq;
};
extern struct nfs_req_st nfs_req_st;
void nfs_rpc_queue_init(void);
static inline void nfs_rpc_q_init(struct req_q *q)
{
glist_init(&q->q);
pthread_spin_init(&q->sp, PTHREAD_PROCESS_PRIVATE);
q->size = 0;
q->waiters = 0;
}
static inline uint32_t nfs_rpc_q_next_slot(void)
{
uint32_t ix = atomic_inc_uint32_t(&nfs_req_st.reqs.ctr);
if (!ix)
ix = atomic_inc_uint32_t(&nfs_req_st.reqs.ctr);
return ix;
}
static inline void nfs_rpc_queue_awaken(void *arg)
{
struct nfs_req_st *st = arg;
struct glist_head *g = NULL;
struct glist_head *n = NULL;
pthread_spin_lock(&st->reqs.sp);
glist_for_each_safe(g, n, &st->reqs.wait_list) {
wait_q_entry_t *wqe = glist_entry(g, wait_q_entry_t, waitq);
pthread_cond_signal(&wqe->lwe.cv);
pthread_cond_signal(&wqe->rwe.cv);
}
pthread_spin_unlock(&st->reqs.sp);
}
#endif /* NFS_REQ_QUEUE_H */