#include <linux/lustre_lite.h>
#include "llite_internal.h"
-static struct ptlrpc_thread ll_capa_thread;
static struct list_head *ll_capa_list = &capa_list[CLIENT_CAPA];
+static struct ptlrpc_thread capa_thread;
+
static struct thread_ctl {
struct completion ctl_starting;
struct completion ctl_finishing;
static inline int have_expired_capa(void)
{
struct obd_capa *ocapa;
+ struct lustre_capa *capa;
int expired = 0;
+ unsigned long expiry;
+ struct timeval tv;
+
ENTRY;
+ do_gettimeofday(&tv);
spin_lock(&capa_lock);
if (!list_empty(ll_capa_list)) {
ocapa = list_entry(ll_capa_list->next, struct obd_capa, c_list);
-
- expired = __capa_is_to_expire(ocapa);
+ expired = __capa_is_to_expire(ocapa, &tv);
+ if (!expired) {
+ capa = &ocapa->c_capa;
+ expiry = expiry_to_jiffies(capa->lc_expiry -
+ capa_pre_expiry(capa));
+ if (time_before(expiry, ll_capa_timer.expires) ||
+ !timer_pending(&ll_capa_timer)) {
+ mod_timer(&ll_capa_timer, expiry);
+ CDEBUG(D_INFO,"ll_capa_timer new expiry: %lu\n",
+ expiry);
+ }
+ }
}
spin_unlock(&capa_lock);
static int inline ll_capa_check_stop(void)
{
- return (ll_capa_thread.t_flags & SVC_STOPPING) ? 1: 0;
+ return (capa_thread.t_flags & SVC_STOPPING) ? 1: 0;
}
static int ll_renew_capa(struct obd_capa *ocapa)
struct inode *inode = ocapa->c_inode;
struct obd_export *md_exp = ll_i2mdexp(inode);
struct ll_inode_info *lli = ll_i2info(inode);
- __u64 valid = 0;
+ __u64 valid = OBD_MD_CAPA;
int rc;
ENTRY;
- valid |= OBD_MD_CAPA;
-
rc = md_getattr(md_exp, &lli->lli_id, valid, NULL, NULL, 0,
0, ocapa, &req);
- if (rc < 0)
- CDEBUG(D_INFO, "md_getattr failed: rc = %d\n", rc);
RETURN(rc);
}
-static int ll_capa_thread_main(void *arg)
+static int ll_capa_thread(void *arg)
{
struct thread_ctl *ctl = arg;
unsigned long flags;
+ int rc;
ENTRY;
{
* letting starting function know, that we are ready and control may be
* returned.
*/
- ll_capa_thread.t_flags = SVC_RUNNING;
+ capa_thread.t_flags = SVC_RUNNING;
complete(&ctl->ctl_starting);
while (1) {
struct l_wait_info lwi = { 0 };
- struct obd_capa *ocapa, *next = NULL;
- int sleep = CAPA_PRE_EXPIRY;
+ struct obd_capa *ocapa, tcapa, *tmp, *next = NULL;
+ unsigned long expiry, sleep = CAPA_PRE_EXPIRY;
+ struct inode *inode;
+ struct timeval tv;
- l_wait_event(ll_capa_thread.t_ctl_waitq,
+ l_wait_event(capa_thread.t_ctl_waitq,
(have_expired_capa() || ll_capa_check_stop()),
&lwi);
+ if (ll_capa_check_stop())
+ break;
+
+ do_gettimeofday(&tv);
spin_lock(&capa_lock);
- list_for_each_entry(ocapa, ll_capa_list, c_list) {
- if (__capa_is_to_expire(ocapa)) {
- /* get capa in case it's deleted */
- __capa_get(ocapa);
+ list_for_each_entry_safe(ocapa, tmp, ll_capa_list, c_list) {
+ if (ocapa->c_capa.lc_flags & CAPA_FL_SHORT)
+ sleep = CAPA_PRE_EXPIRY_SHORT;
+ if (ocapa->c_capa.lc_op == CAPA_TRUNC)
+ continue;
+
+ if (capa_expired(&ocapa->c_capa)) {
+ capa_put_nolock(ocapa);
+ continue;
+ }
+
+ if (__capa_is_to_expire(ocapa, &tv)) {
+ inode = igrab(ocapa->c_inode);
+ if (inode == NULL) {
+ DEBUG_CAPA(D_ERROR, &ocapa->c_capa,
+ "igrab failed for");
+ continue;
+ }
+
+ tcapa = *ocapa;
spin_unlock(&capa_lock);
- ll_renew_capa(ocapa);
- capa_put(ocapa, CLIENT_CAPA);
+
+ rc = ll_renew_capa(&tcapa);
+ iput(inode);
+
spin_lock(&capa_lock);
} else {
next = ocapa;
break;
}
}
+
if (next) {
- mod_timer(&ll_capa_timer,
- expiry_to_jiffies(next->c_capa.lc_expiry));
- if (next->c_capa.lc_flags & CAPA_FL_NOROUND)
- sleep = CAPA_PRE_EXPIRY_NOROUND;
+ struct lustre_capa *capa = &next->c_capa;
+
+ expiry = expiry_to_jiffies(capa->lc_expiry -
+ capa_pre_expiry(capa));
+ if (time_before(expiry, ll_capa_timer.expires) ||
+ !timer_pending(&ll_capa_timer)) {
+ mod_timer(&ll_capa_timer, expiry);
+ CDEBUG(D_INFO,"ll_capa_timer new expiry: %lu\n",
+ expiry);
+ }
}
spin_unlock(&capa_lock);
- if (ll_capa_check_stop())
- break;
-
/* wait ll_renew_capa finish */
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(sleep * HZ);
}
- ll_capa_thread.t_flags = SVC_STOPPED;
+ capa_thread.t_flags = SVC_STOPPED;
/* this is SMP-safe way to finish thread. */
complete_and_exit(&ctl->ctl_finishing, 0);
void ll_capa_timer_callback(unsigned long unused)
{
ENTRY;
- wake_up(&ll_capa_thread.t_ctl_waitq);
+ wake_up(&capa_thread.t_ctl_waitq);
EXIT;
}
-int ll_capa_start_thread(void)
+int ll_capa_thread_start(void)
{
int rc;
ENTRY;
- LASSERT(ll_capa_thread.t_flags == 0);
+ LASSERT(capa_thread.t_flags == 0);
init_completion(&ll_capa_ctl.ctl_starting);
init_completion(&ll_capa_ctl.ctl_finishing);
- init_waitqueue_head(&ll_capa_thread.t_ctl_waitq);
+ init_waitqueue_head(&capa_thread.t_ctl_waitq);
- rc = kernel_thread(ll_capa_thread_main, &ll_capa_ctl,
+ rc = kernel_thread(ll_capa_thread, &ll_capa_ctl,
(CLONE_VM | CLONE_FILES));
if (rc < 0) {
CERROR("cannot start expired capa thread, "
RETURN(rc);
}
wait_for_completion(&ll_capa_ctl.ctl_starting);
- LASSERT(ll_capa_thread.t_flags == SVC_RUNNING);
+ LASSERT(capa_thread.t_flags == SVC_RUNNING);
RETURN(0);
}
-void ll_capa_stop_thread(void)
+void ll_capa_thread_stop(void)
{
ENTRY;
- ll_capa_thread.t_flags = SVC_STOPPING;
- wake_up(&ll_capa_thread.t_ctl_waitq);
+ capa_thread.t_flags = SVC_STOPPING;
+ wake_up(&capa_thread.t_ctl_waitq);
wait_for_completion(&ll_capa_ctl.ctl_finishing);
- LASSERT(ll_capa_thread.t_flags == SVC_STOPPED);
- ll_capa_thread.t_flags = 0;
+ LASSERT(capa_thread.t_flags == SVC_STOPPED);
+ capa_thread.t_flags = 0;
EXIT;
}
-int ll_set_och_capa(struct inode *inode, struct lookup_intent *it,
- struct obd_client_handle *och)
+int ll_set_capa(struct inode *inode, struct lookup_intent *it,
+ struct obd_client_handle *och)
{
struct ptlrpc_request *req = LUSTRE_IT(it)->it_data;
- struct ll_inode_info *lli = ll_i2info(inode);
struct mds_body *body;
struct lustre_capa *capa;
- __u64 mdsid = lli->lli_id.li_fid.lf_group;
- unsigned long ino = lli->lli_id.li_stc.u.e3s.l3s_ino;
- int capa_op = (it->it_flags & MAY_WRITE) ? MAY_WRITE : MAY_READ;
+ struct obd_capa *ocapa;
+ struct ll_inode_info *lli = ll_i2info(inode);
unsigned long expiry;
- int rc = 0;
- ENTRY;
+
+ if (!S_ISREG(inode->i_mode))
+ return 0;
+
+ /* GNS code path will have no req */
+ if (!req)
+ return 0;
body = lustre_msg_buf(req->rq_repmsg, 1, sizeof (*body));
LASSERT(body != NULL); /* reply already checked out */
LASSERT_REPSWABBED(req, 1); /* and swabbed down */
+ if (!(body->valid & OBD_MD_CAPA)) {
+ if (atomic_read(&ll_capa_stat))
+ DEBUG_REQ(D_ERROR, req,
+ "no capa for (uid %u, op %d, "DLID4"\n",
+ (unsigned)current->uid, it->it_flags,
+ OLID4(&lli->lli_id));
+
+ return 0;
+ }
+
+ ENTRY;
+
capa = lustre_msg_buf(req->rq_repmsg, 7, sizeof (*capa));
LASSERT(capa != NULL); /* reply already checked out */
LASSERT_REPSWABBED(req, 7); /* and swabbed down */
- och->och_capa = capa_get(current->uid, capa_op, mdsid, ino,
- CLIENT_CAPA, capa, inode, &body->handle);
- if (!och->och_capa)
- rc = -ENOMEM;
+ ocapa = capa_renew(capa, CLIENT_CAPA);
+ if (!ocapa)
+ RETURN(-ENOMEM);
+
+ spin_lock(&capa_lock);
+ ocapa->c_inode = inode;
+ ocapa->c_handle = och->och_fh;
+ spin_unlock(&capa_lock);
+
+ spin_lock(&lli->lli_lock);
+ /* in case it was linked to lli_capas already */
+ if (list_empty(&ocapa->c_lli_list))
+ list_add(&ocapa->c_lli_list, &lli->lli_capas);
+ spin_unlock(&lli->lli_lock);
expiry = expiry_to_jiffies(capa->lc_expiry - capa_pre_expiry(capa));
+
+ spin_lock(&capa_lock);
if (time_before(expiry, ll_capa_timer.expires) ||
- !timer_pending(&ll_capa_timer))
+ !timer_pending(&ll_capa_timer)) {
mod_timer(&ll_capa_timer, expiry);
+ CDEBUG(D_INFO, "ll_capa_timer new expiry: %lu\n", expiry);
+ }
+ spin_unlock(&capa_lock);
- RETURN(rc);
+ RETURN(0);
+}
+
+int ll_set_trunc_capa(struct ptlrpc_request *req, int offset, struct inode *inode)
+{
+ struct mds_body *body;
+ struct obd_capa *ocapa;
+ struct lustre_capa *capa;
+ struct ll_inode_info *lli = ll_i2info(inode);
+
+ body = lustre_msg_buf(req->rq_repmsg, offset, sizeof(*body));
+ if (!body)
+ return -ENOMEM;
+
+ if (!(body->valid & OBD_MD_CAPA))
+ return 0;
+
+ ENTRY;
+ capa = (struct lustre_capa *)lustre_swab_repbuf(req, offset + 1,
+ sizeof(*capa), lustre_swab_lustre_capa);
+ if (!capa)
+ RETURN(-ENOMEM);
+
+ ocapa = capa_renew(capa, CLIENT_CAPA);
+ if (!ocapa)
+ RETURN(-ENOMEM);
+
+ spin_lock(&lli->lli_lock);
+ /* in case it was linked to lli_capas already */
+ if (list_empty(&ocapa->c_lli_list))
+ list_add(&ocapa->c_lli_list, &lli->lli_capas);
+ spin_unlock(&lli->lli_lock);
+
+ RETURN(0);
+}
+
+struct obd_capa *ll_get_capa(struct inode *inode, uid_t uid, int op)
+{
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct obd_capa *ocapa, *tmp;
+ ENTRY;
+
+ list_for_each_entry_safe(ocapa, tmp, &lli->lli_capas, c_lli_list) {
+ if (ocapa->c_capa.lc_ruid != uid)
+ continue;
+ if (ocapa->c_capa.lc_op != op)
+ continue;
+
+ RETURN(ocapa);
+ }
+
+ if (atomic_read(&ll_capa_stat)) {
+ CDEBUG(D_ERROR, "can't find capa for (uid %u, op %d, mdsid "
+ LPU64", ino %u igen %u) failed.\n",
+ (unsigned)uid, op, id_group(&lli->lli_id),
+ (unsigned)id_ino(&lli->lli_id), id_gen(&lli->lli_id));
+ atomic_set(&ll_capa_stat, 0);
+ }
+
+ RETURN(NULL);
}