<commit_before>/* $Id$ */
/*
 * %GPL_START_LICENSE%
 * ---------------------------------------------------------------------
 * Copyright 2015-2016, Google, Inc.
 * Copyright 2008-2016, Pittsburgh Supercomputing Center
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License contained in the file
 * `COPYING-GPL' at the top of this distribution or at
 * https://www.gnu.org/licenses/gpl-2.0.html for more details.
 * ---------------------------------------------------------------------
 * %END_LICENSE%
 */

/*
 * Logic for bmap flushing: sending RPCs of dirty data modified by
 * clients to the IO systems they are bound to.  Write coalescing
 * (bwc) occurs to reduce RPC overhead.
 */

#define PSC_SUBSYS SLSS_BMAP
#include "slsubsys.h"

#include <sys/time.h>
#include <sys/types.h>

#include <stdlib.h>

#include "pfl/cdefs.h"
#include "pfl/completion.h"
#include "pfl/ctlsvr.h"
#include "pfl/dynarray.h"
#include "pfl/fault.h"
#include "pfl/fcntl.h"
#include "pfl/fsmod.h"
#include "pfl/listcache.h"
#include "pfl/log.h"
#include "pfl/rpc.h"
#include "pfl/rpclog.h"
#include "pfl/rsx.h"
#include "pfl/tree.h"
#include "pfl/treeutil.h"

#include "bmap.h"
#include "bmap_cli.h"
#include "pgcache.h"
#include "mount_slash.h"
#include "rpc_cli.h"
#include "slashrpc.h"
#include "slconfig.h"

struct timespec			 msl_bflush_timeout = { 1, 0L };
struct timespec			 msl_bflush_maxage = { 0, 10000000L };	/* 10 milliseconds */
struct psc_listcache		 msl_bmapflushq;
struct psc_listcache		 msl_bmaptimeoutq;

int				 msl_max_nretries = 256;

#define MIN_COALESCE_RPC_SZ	LNET_MTU

struct psc_waitq		 slc_bflush_waitq = PSC_WAITQ_INIT;
psc_spinlock_t			 slc_bflush_lock = SPINLOCK_INIT;
int				 slc_bflush_tmout_flags;

int64_t				 slc_pending_writes;
psc_spinlock_t			 slc_pending_writes_lock = SPINLOCK_INIT;

psc_atomic32_t			 slc_write_coalesce_max;

__static int
bmap_flush_biorq_expired(const struct bmpc_ioreq *a)
{
	struct timespec ts;

	if (a->biorq_flags & BIORQ_EXPIRE)
		return (1);

	PFL_GETTIMESPEC(&ts);
	/* XXX timespeccmp(&a->biorq_expire, &ts, <) */
	if ((a->biorq_expire.tv_sec < ts.tv_sec ||
	    (a->biorq_expire.tv_sec == ts.tv_sec &&
	     a->biorq_expire.tv_nsec <= ts.tv_nsec)))
		return (1);

	return (0);
}

/*
 * Manually expire all bmaps attached to a file.  The RPC flusher will
 * soon notice and flush any pending data.
 */
void
bmap_free_all_locked(struct fidc_membh *f)
{
	struct bmap_cli_info *bci;
	struct bmap *b;

	FCMH_LOCK_ENSURE(f);

	/* 03/18/2016: Hit SIGSEGV when called from do_setattr() */
	RB_FOREACH(b, bmaptree, &f->fcmh_bmaptree) {
		DEBUG_BMAP(PLL_DIAG, b, "mark bmap free");

		/*
		 * The MDS truncates the SLASH2 metadata file on a full
		 * truncate.  We need to throw away leases and request a
		 * new lease later, so that the MDS has a chance to
		 * update its metadata file on-disk.  Otherwise, we can
		 * use an existing lease to write the file and can not
		 * update the metadata file even if the bmap is still
		 * cached at the MDS because the generation # has been
		 * bumped for the full truncate.
		 *
		 * Finally, a read comes in, we request a read bmap.  At
		 * this point, all bmaps of the file have been freed at
		 * both MDS and client.  And the MDS cannot find a
		 * replica for a bmap in the metafile.
		 */
		BMAP_LOCK(b);
		bci = bmap_2_bci(b);
		PFL_GETTIMESPEC(&bci->bci_etime);
		BMAP_ULOCK(b);
	}
	psc_waitq_wakeall(&msl_bmaptimeoutq.plc_wq_empty);
}


/*
 * Pin (mark read-only) all pages attached to a bmap write coalescer.
 */
void
bwc_pin_pages(struct bmpc_write_coalescer *bwc)
{
	struct bmap_pagecache_entry *pg;
	int i;

	for (i = 0; i < bwc->bwc_nbmpces; i++) {
		pg = bwc->bwc_bmpces[i];
		BMPCE_LOCK(pg);
		pg->bmpce_pins++;
		BMPCE_ULOCK(pg);
	}
}

/*
 * Unpin (release) all pages attached to a bmap write coalescer.
 */
void<commit_msg>Manual move a deadlock fix from development tree during bmap_free_all_locked()wq<commit_after>/* $Id$ */
/*
 * %GPL_START_LICENSE%
 * ---------------------------------------------------------------------
 * Copyright 2015-2016, Google, Inc.
 * Copyright 2008-2016, Pittsburgh Supercomputing Center
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License contained in the file
 * `COPYING-GPL' at the top of this distribution or at
 * https://www.gnu.org/licenses/gpl-2.0.html for more details.
 * ---------------------------------------------------------------------
 * %END_LICENSE%
 */

/*
 * Logic for bmap flushing: sending RPCs of dirty data modified by
 * clients to the IO systems they are bound to.  Write coalescing
 * (bwc) occurs to reduce RPC overhead.
 */

#define PSC_SUBSYS SLSS_BMAP
#include "slsubsys.h"

#include <sys/time.h>
#include <sys/types.h>

#include <stdlib.h>

#include "pfl/cdefs.h"
#include "pfl/completion.h"
#include "pfl/ctlsvr.h"
#include "pfl/dynarray.h"
#include "pfl/fault.h"
#include "pfl/fcntl.h"
#include "pfl/fsmod.h"
#include "pfl/listcache.h"
#include "pfl/log.h"
#include "pfl/rpc.h"
#include "pfl/rpclog.h"
#include "pfl/rsx.h"
#include "pfl/tree.h"
#include "pfl/treeutil.h"

#include "bmap.h"
#include "bmap_cli.h"
#include "pgcache.h"
#include "mount_slash.h"
#include "rpc_cli.h"
#include "slashrpc.h"
#include "slconfig.h"

struct timespec			 msl_bflush_timeout = { 1, 0L };
struct timespec			 msl_bflush_maxage = { 0, 10000000L };	/* 10 milliseconds */
struct psc_listcache		 msl_bmapflushq;
struct psc_listcache		 msl_bmaptimeoutq;

int				 msl_max_nretries = 256;

#define MIN_COALESCE_RPC_SZ	LNET_MTU

struct psc_waitq		 slc_bflush_waitq = PSC_WAITQ_INIT;
psc_spinlock_t			 slc_bflush_lock = SPINLOCK_INIT;
int				 slc_bflush_tmout_flags;

int64_t				 slc_pending_writes;
psc_spinlock_t			 slc_pending_writes_lock = SPINLOCK_INIT;

psc_atomic32_t			 slc_write_coalesce_max;

__static int
bmap_flush_biorq_expired(const struct bmpc_ioreq *a)
{
	struct timespec ts;

	if (a->biorq_flags & BIORQ_EXPIRE)
		return (1);

	PFL_GETTIMESPEC(&ts);
	/* XXX timespeccmp(&a->biorq_expire, &ts, <) */
	if ((a->biorq_expire.tv_sec < ts.tv_sec ||
	    (a->biorq_expire.tv_sec == ts.tv_sec &&
	     a->biorq_expire.tv_nsec <= ts.tv_nsec)))
		return (1);

	return (0);
}

/*
 * Manually expire all bmaps attached to a file.  The RPC flusher will
 * soon notice and flush any pending data.
 */
void
bmap_free_all_locked(struct fidc_membh *f)
{
	int redo = 0;
	struct bmap_cli_info *bci;
	struct bmap *b;
	
 retry:

	FCMH_LOCK_ENSURE(f);

	/* 03/18/2016: Hit SIGSEGV when called from do_setattr() */
	RB_FOREACH(b, bmaptree, &f->fcmh_bmaptree) {
		DEBUG_BMAP(PLL_DIAG, b, "mark bmap free");

		/*
		 * The MDS truncates the SLASH2 metadata file on a full
		 * truncate.  We need to throw away leases and request a
		 * new lease later, so that the MDS has a chance to
		 * update its metadata file on-disk.  Otherwise, we can
		 * use an existing lease to write the file and can not
		 * update the metadata file even if the bmap is still
		 * cached at the MDS because the generation # has been
		 * bumped for the full truncate.
		 *
		 * Finally, a read comes in, we request a read bmap.  At
		 * this point, all bmaps of the file have been freed at
		 * both MDS and client.  And the MDS cannot find a
		 * replica for a bmap in the metafile.
		 */
		if (!BMAP_TRYLOCK(b)) {
			redo = 1;
			break;
		}
		bci = bmap_2_bci(b);
		PFL_GETTIMESPEC(&bci->bci_etime);
		BMAP_ULOCK(b);
	}
	/*
 	 * Need to race with the bmap timeout code path.
 	 */
	if (redo) {
		redo = 0;
		FCMH_ULOCK(f);
		usleep(10);
		FCMH_LOCK(f);
		goto retry;
	}
	psc_waitq_wakeall(&msl_bmaptimeoutq.plc_wq_empty);
}


/*
 * Pin (mark read-only) all pages attached to a bmap write coalescer.
 */
void
bwc_pin_pages(struct bmpc_write_coalescer *bwc)
{
	struct bmap_pagecache_entry *pg;
	int i;

	for (i = 0; i < bwc->bwc_nbmpces; i++) {
		pg = bwc->bwc_bmpces[i];
		BMPCE_LOCK(pg);
		pg->bmpce_pins++;
		BMPCE_ULOCK(pg);
	}
}

/*
 * Unpin (release) all pages attached to a bmap write coalescer.
 */
void
{'fraction_non_alphanumeric': 0.1349161054674124, 'fraction_numerical': 0.012669786554046342, 'mean_word_length': 3.2783203125, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 29, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '787002', 'n_tokens_mistral': 3524, 'n_tokens_neox': 3263, 'n_words': 948}