text: /*
  **
  **  OO_Copyright_BEGIN
  **
  **
  **  Copyright 2010, 2019 IBM Corp. All rights reserved.
  **
  **  Redistribution and use in source and binary forms, with or without
  **   modification, are permitted provided that the following conditions
  **  are met:
  **  1. Redistributions of source code must retain the above copyright
  **     notice, this list of conditions and the following disclaimer.
  **  2. Redistributions in binary form must reproduce the above copyright
  **     notice, this list of conditions and the following disclaimer in the
  **  documentation and/or other materials provided with the distribution.
  **  3. Neither the name of the copyright holder nor the names of its
  **     contributors may be used to endorse or promote products derived from
  **     this software without specific prior written permission.
  **
  **  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
  **  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  **  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  **  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  **  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  **  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  **  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  **  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  **  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  **  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  **  POSSIBILITY OF SUCH DAMAGE.
  **
  **
  **  OO_Copyright_END
  **
  *************************************************************************************
  **
  ** COMPONENT NAME:  IBM Linear Tape File System
  **
  ** FILE NAME:       periodic_sync.c
  **
  ** DESCRIPTION:     Implements the periodic sync feature
  **
  ** AUTHOR:          Atsushi Abe
  **                  IBM Yamato, Japan
  **                  PISTE@jp.ibm.com
  *************************************************************************************
  */
  
  #include "ltfs.h"
  #include "ltfs_fsops.h"
  
  /**
   * Periodic sync scheduler private data structure.
   */
  struct periodic_sync_data {
  	ltfs_thread_cond_t   periodic_sync_thread_cond;  /**< Used to wake up the periodic sync thread */
  	ltfs_thread_mutex_t  periodic_sync_thread_mutex; /**< Used to handle the periodic sync thread */
  	ltfs_thread_t        periodic_sync_thread_id;    /**< Thread id of the periodic sync thread */
  	bool             keepalive;                  /**< Used to terminate the background thread */
  	int              period_sec;                 /**< Period between sync (sec) */
  	struct ltfs_volume *vol;                     /**< A reference to the LTFS volume structure */
  };
  
  /**
   * Main routine for periodic sync.
   * @param data Periodic sync private data
   * @return NULL.
   */
  #define FUSE_REQ_ENTER(r)   REQ_NUMBER(REQ_STAT_ENTER, REQ_FUSE, r)
  #define FUSE_REQ_EXIT(r)    REQ_NUMBER(REQ_STAT_EXIT,  REQ_FUSE, r)
  
  #define REQ_SYNC        fffe
  
  ltfs_thread_return periodic_sync_thread(void* data)
  {
  	struct periodic_sync_data *priv = (struct periodic_sync_data *) data;
  	struct timeval now;
  	int ret;
  
  	ltfs_thread_mutex_lock(&priv->periodic_sync_thread_mutex);
  	while (priv->keepalive && gettimeofday(&now, NULL) == 0) {
  		ltfs_thread_cond_timedwait(&priv->periodic_sync_thread_cond,
  								   &priv->periodic_sync_thread_mutex,
  								   priv->period_sec);
  		if (! priv->keepalive)
  			break;
  
  		ltfs_request_trace(FUSE_REQ_ENTER(REQ_SYNC), 0, 0);
  
  		ltfsmsg(LTFS_DEBUG, 17067D, "Sync-by-Time");
  		ret = ltfs_fsops_flush(NULL, false, priv->vol);
  		if (ret < 0) {
  			/* Failed to flush file data */
  			ltfsmsg(LTFS_WARN, 17063W, __FUNCTION__);
  		}
  
  		ret = ltfs_sync_index(SYNC_PERIODIC, true, priv->vol);
  		if (ret < 0) {
  			ltfsmsg(LTFS_INFO, 11030I, ret);
  			priv->keepalive = false;
  		}
  
  		ltfs_request_trace(FUSE_REQ_EXIT(REQ_SYNC), ret, 0);
  	}
  	ltfs_thread_mutex_unlock(&priv->periodic_sync_thread_mutex);
  
  	ltfsmsg(LTFS_DEBUG, 17064D, "Sync-by-Time");
  	ltfs_thread_exit();
  
  	return LTFS_THREAD_RC_NULL;
  }
  
  /**
   * Verifies if the periodic sync thread is currently running.
   * @param vol LTFS volume
   * @return true if the thread is running, false if not.
   */
  bool periodic_sync_thread_initialized(struct ltfs_volume *vol)
  {
  	struct periodic_sync_data *priv = vol ? vol->periodic_sync_handle : NULL;
  	bool initialized = false;
  
  	if (priv) {
  		ltfs_thread_mutex_lock(&priv->periodic_sync_thread_mutex);
  		initialized = priv->keepalive;
  		ltfs_thread_mutex_unlock(&priv->periodic_sync_thread_mutex);
  	}
  
  	return initialized;
  }
  
  /**
   * Initialize the periodic sync thread.
   * @param sec timer in which the syncing will be performed
   * @param vol LTFS volume
   * @return 0 on success or a negative value on error.
   */
  int periodic_sync_thread_init(int sec, struct ltfs_volume *vol)
  {
  	int ret;
  	struct periodic_sync_data *priv;
  
  	CHECK_ARG_NULL(vol, -LTFS_NULL_ARG);
  
  	priv = calloc(1, sizeof(struct periodic_sync_data));
  	if (! priv) {
  		ltfsmsg(LTFS_ERR, 10001E, "periodic_sync_thread_init: periodic sync data");
  		return -LTFS_NO_MEMORY;
  	}
  
  	priv->vol = vol;
  	priv->keepalive = true;
  	priv->period_sec = sec;
  
  	ret = ltfs_thread_cond_init(&priv->periodic_sync_thread_cond);
  	if (ret) {
  		ltfsmsg(LTFS_ERR, 10003E, ret);
  		free(priv);
  		return -ret;
  	}
  	ret = ltfs_thread_mutex_init(&priv->periodic_sync_thread_mutex);
  	if (ret) {
  		ltfsmsg(LTFS_ERR, 10002E, ret);
  		ltfs_thread_cond_destroy(&priv->periodic_sync_thread_cond);
  		free(priv);
  		return -ret;
  	}
  	ret = ltfs_thread_create(&priv->periodic_sync_thread_id, periodic_sync_thread, priv);
  	if (ret < 0) {
  		/* Failed to spawn the periodic sync thread (%d) */
  		ltfsmsg(LTFS_ERR, 17099E, ret);
  		ltfs_thread_mutex_destroy(&priv->periodic_sync_thread_mutex);
  		ltfs_thread_cond_destroy(&priv->periodic_sync_thread_cond);
  		free(priv);
  		return -ret;
  	}
  
  	ltfsmsg(LTFS_DEBUG, 17065D);
  	vol->periodic_sync_handle = priv;
  
  	return 0;
  }
  
  /**
   * Destroy the periodic sync thread.
   * @param vol LTFS volume
   * @return 0 on success or a negative value on error.
   */
  int periodic_sync_thread_destroy(struct ltfs_volume *vol)
  {
  	struct periodic_sync_data *priv = vol ? vol->periodic_sync_handle : NULL;
  
  	CHECK_ARG_NULL(vol, -LTFS_NULL_ARG);
  	CHECK_ARG_NULL(priv, -LTFS_NULL_ARG);
  
  	ltfs_thread_mutex_lock(&priv->periodic_sync_thread_mutex);
  	priv->keepalive = false;
  	ltfs_thread_cond_signal(&priv->periodic_sync_thread_cond);
  	ltfs_thread_mutex_unlock(&priv->periodic_sync_thread_mutex);
  
  	ltfs_thread_join(priv->periodic_sync_thread_id);
  	ltfs_thread_cond_destroy(&priv->periodic_sync_thread_cond);
  	ltfs_thread_mutex_destroy(&priv->periodic_sync_thread_mutex);
  	free(priv);
  
  	vol->periodic_sync_handle = NULL;
  
  	ltfsmsg(LTFS_DEBUG, 17066D);
  	return 0;
  }
  