/* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * BSD 3 Clause License * * Copyright (c) 2007, The Storage Networking Industry Association. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - 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. * * - Neither the name of The Storage Networking Industry Association (SNIA) * 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 OWNER 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. */ #include #include "tlm.h" #include "tlm_proto.h" #include extern tlm_chain_link_t *tlm_un_ref(tlm_chain_link_t *old_top, tlm_chain_link_t *link); static tlm_info_t tlm_info; /* * Mutex for concurrent access to job_stats */ mutex_t jstat_mtx; /* * get the number of libraries */ int tlm_library_count(void) { int lib; tlm_library_t *library; for (lib = 1; lib <= tlm_info.ti_library_count; lib++) { library = tlm_library(lib); if (library != NULL && library->tl_drive_count == 0) { return (0); } } return (tlm_info.ti_library_count); } /* * get the library whose number matches */ tlm_library_t * tlm_library(int lib) { tlm_library_t *library = tlm_info.ti_library; while (library != NULL) { if (library->tl_number == lib) { return (library); } library = library->tl_next; } errno = TLM_ERROR_RANGE; return (NULL); } /* * get the info about this drive */ tlm_drive_t * tlm_drive(int lib, int drv) { tlm_drive_t *drive; tlm_library_t *library = tlm_library(lib); if (library == NULL) { return (NULL); } drive = library->tl_drive; while (drive != NULL) { if (drv == drive->td_number) { return (drive); } drive = drive->td_next; } return (NULL); } /* * get the info about this slot */ tlm_slot_t * tlm_slot(int lib, int slt) { tlm_slot_t *slot = NULL; tlm_library_t *library = tlm_library(lib); if (library != NULL) slot = library->tl_slot; while (slot != NULL) { if (slt == slot->ts_number) { return (slot); } slot = slot->ts_next; } return (NULL); } /* * add a link to the INFO chain */ tlm_job_stats_t * tlm_new_job_stats(char *name) { tlm_chain_link_t *new_link; tlm_job_stats_t *job_stats; new_link = ndmp_malloc(sizeof (tlm_chain_link_t)); if (new_link == 0) return (0); job_stats = ndmp_malloc(sizeof (tlm_job_stats_t)); if (job_stats == 0) { free(new_link); return (0); } new_link->tc_ref_count = 1; new_link->tc_data = (void *)job_stats; (void) strlcpy(job_stats->js_job_name, name, TLM_MAX_BACKUP_JOB_NAME); (void) mutex_lock(&jstat_mtx); if (tlm_info.ti_job_stats == 0) { new_link->tc_next = new_link; new_link->tc_prev = new_link; } else { tlm_chain_link_t *next_link = tlm_info.ti_job_stats; tlm_chain_link_t *prev_link = next_link->tc_prev; new_link->tc_next = next_link; new_link->tc_prev = prev_link; prev_link->tc_next = new_link; next_link->tc_prev = new_link; } tlm_info.ti_job_stats = new_link; (void) mutex_unlock(&jstat_mtx); return (job_stats); } /* * make sure this Job Stats buffer is not deleted while we use it */ tlm_job_stats_t * tlm_ref_job_stats(char *name) { static tlm_job_stats_t fake_job_stats; tlm_chain_link_t *link; (void) mutex_lock(&jstat_mtx); link = tlm_info.ti_job_stats; if (link == 0) { /* * our tables are empty */ (void) mutex_unlock(&jstat_mtx); return (&fake_job_stats); } do { tlm_job_stats_t *job_stats; job_stats = (tlm_job_stats_t *)link->tc_data; if (strcmp(job_stats->js_job_name, name) == 0) { link->tc_ref_count++; (void) mutex_unlock(&jstat_mtx); return (job_stats); } link = link->tc_next; } while (link != tlm_info.ti_job_stats); NDMP_LOG(LOG_DEBUG, "TAPE BACKUP> Ref for job [%s] was not found", name); (void) mutex_unlock(&jstat_mtx); return (&fake_job_stats); } /* * remove a link to the INFO chain */ void tlm_un_ref_job_stats(char *name) { tlm_chain_link_t *link; (void) mutex_lock(&jstat_mtx); link = tlm_info.ti_job_stats; if (link == 0) { NDMP_LOG(LOG_DEBUG, "TAPE BACKUP>" " Internal error for job [%s], could not delete", name); return; } do { tlm_job_stats_t *job_stats; job_stats = (tlm_job_stats_t *)link->tc_data; if (strcmp(job_stats->js_job_name, name) == 0) { tlm_info.ti_job_stats = tlm_un_ref(tlm_info.ti_job_stats, link); (void) mutex_unlock(&jstat_mtx); return; } link = link->tc_next; } while (link != tlm_info.ti_job_stats); (void) mutex_unlock(&jstat_mtx); NDMP_LOG(LOG_DEBUG, "TAPE BACKUP> Delete for job [%s] was not found", name); } /* * one party does not care about this blob, can we let it go? */ tlm_chain_link_t * tlm_un_ref(tlm_chain_link_t *old_top, tlm_chain_link_t *link) { tlm_chain_link_t *chain_link = old_top; tlm_chain_link_t *new_top; /* * count down the number of * interested parties for this blob */ link->tc_ref_count--; if (link->tc_ref_count > 0) { /* * there is still interest in this blob, * no change yet * * returning "old_top" means there is no change in the links */ return (old_top); } /* * no one cares about this data anymore * find out how to delete it */ do { if (chain_link == link) { tlm_chain_link_t *next; tlm_chain_link_t *prev; /* * If there are one or two elements in the list, then * the prev and next pointers point to one element in * the list, the element itself and the other element * correspondingly. So we must distinguish if there * are only one or two elements in the list. If * either of the 'prev' or 'next' pointers point to * the link itself, then we have only one element in * the list. */ if (link->tc_next == link->tc_prev && link->tc_next == link) { /* * there is only this one link in the chain * delete this and the chain is empty */ new_top = 0; } else { new_top = link->tc_next; } next = link->tc_next; prev = link->tc_prev; prev->tc_next = next; next->tc_prev = prev; free(link->tc_data); free(link); return (new_top); } chain_link = chain_link->tc_next; } while (chain_link != old_top); NDMP_LOG(LOG_DEBUG, "TAPE BACKUP> un_ref target not found."); return (old_top); } /* * the following section is global, but not really part of the * public interface. Use of this outside of the tlm_*.c files * is for special cases only. */ /* * add a new tape library data blob to the list of libraries * returns the new tape library data blob just created */ int tlm_insert_new_library(scsi_link_t *slink) { tlm_library_t **p_library = &tlm_info.ti_library; tlm_library_t *library = ndmp_malloc(sizeof (tlm_library_t)); while (*p_library != NULL) { p_library = &(*p_library)->tl_next; } tlm_info.ti_library_count++; library->tl_number = tlm_info.ti_library_count; library->tl_slink = slink; library->tl_capability_robot = TRUE; *p_library = library; return (library->tl_number); } /* * add a new tape drive data blob to the list of drives in a library * returns the new tape drive data blob just created */ int tlm_insert_new_drive(int lib) { tlm_library_t *library = tlm_library(lib); tlm_drive_t *drive = ndmp_malloc(sizeof (tlm_drive_t)); tlm_drive_t **p_drive = &library->tl_drive; while (*p_drive != NULL) { p_drive = &(*p_drive)->td_next; } library->tl_drive_count++; library->tl_capability_drives = TRUE; drive->td_library = library; drive->td_number = library->tl_drive_count; *p_drive = drive; return (drive->td_number); } /* * add a new tape slot data blob to the list of slots in a library * returns the new tape slot data blob just created */ int tlm_insert_new_slot(int lib) { tlm_library_t *library = tlm_library(lib); tlm_slot_t *slot = ndmp_malloc(sizeof (tlm_slot_t)); tlm_slot_t **p_slot = &library->tl_slot; while (*p_slot != NULL) { p_slot = &(*p_slot)->ts_next; } library->tl_slot_count++; library->tl_capability_slots = TRUE; slot->ts_library = library; slot->ts_number = library->tl_slot_count; *p_slot = slot; return (slot->ts_number); }