diff options
Diffstat (limited to 'tools/libxc/ia64/xc_ia64_linux_save.c')
-rw-r--r-- | tools/libxc/ia64/xc_ia64_linux_save.c | 801 |
1 files changed, 0 insertions, 801 deletions
diff --git a/tools/libxc/ia64/xc_ia64_linux_save.c b/tools/libxc/ia64/xc_ia64_linux_save.c deleted file mode 100644 index 3440da343a..0000000000 --- a/tools/libxc/ia64/xc_ia64_linux_save.c +++ /dev/null @@ -1,801 +0,0 @@ -/****************************************************************************** - * xc_ia64_linux_save.c - * - * Save the state of a running Linux session. - * - * This library 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; - * version 2.1 of the License. - * - * This library 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 - * - * Copyright (c) 2003, K A Fraser. - * Rewritten for ia64 by Tristan Gingold <tristan.gingold@bull.net> - * - * Copyright (c) 2007 Isaku Yamahata <yamahata@valinux.co.jp> - * Use foreign p2m exposure. - * VTi domain support. - */ - -#include <inttypes.h> -#include <time.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/time.h> - -#include "xg_private.h" -#include "xc_bitops.h" -#include "xc_ia64.h" -#include "xc_ia64_save_restore.h" -#include "xc_efi.h" -#include "xen/hvm/params.h" - -/* -** Default values for important tuning parameters. Can override by passing -** non-zero replacement values to xc_linux_save(). -** -** XXX SMH: should consider if want to be able to override MAX_MBIT_RATE too. -** -*/ -#define DEF_MAX_ITERS (4 - 1) /* limit us to 4 times round loop */ -#define DEF_MAX_FACTOR 3 /* never send more than 3x nr_pfns */ - -/* -** During (live) save/migrate, we maintain a number of bitmaps to track -** which pages we have to send, and to skip. -*/ - -static int -suspend_and_state(int (*suspend)(void*), void* data, - xc_interface *xch, int io_fd, - int dom, xc_dominfo_t *info) -{ - if ( !(*suspend)(data) ) { - ERROR("Suspend request failed"); - return -1; - } - - if ( (xc_domain_getinfo(xch, dom, 1, info) != 1) || - !info->shutdown || (info->shutdown_reason != SHUTDOWN_suspend) ) { - ERROR("Could not get domain info"); - return -1; - } - - return 0; -} - -static inline int -md_is_not_ram(const efi_memory_desc_t *md) -{ - return ((md->type != EFI_CONVENTIONAL_MEMORY) || - (md->attribute != EFI_MEMORY_WB) || - (md->num_pages == 0)); -} - -/* - * Send through a list of all the PFNs that were not in map at the close. - * We send pages which was allocated. However balloon driver may - * decreased after sending page. So we have to check the freed - * page after pausing the domain. - */ -static int -xc_ia64_send_unallocated_list(xc_interface *xch, int io_fd, - struct xen_ia64_p2m_table *p2m_table, - xen_ia64_memmap_info_t *memmap_info, - void *memmap_desc_start, void *memmap_desc_end) -{ - void *p; - efi_memory_desc_t *md; - - unsigned long N; - unsigned long pfntab[1024]; - unsigned int j; - - j = 0; - for (p = memmap_desc_start; - p < memmap_desc_end; - p += memmap_info->efi_memdesc_size) { - md = p; - - if (md_is_not_ram(md)) - continue; - - for (N = md->phys_addr >> PAGE_SHIFT; - N < (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >> - PAGE_SHIFT; - N++) { - if (!xc_ia64_p2m_allocated(p2m_table, N)) - j++; - } - } - if (write_exact(io_fd, &j, sizeof(unsigned int))) { - ERROR("Error when writing to state file (6a)"); - return -1; - } - - j = 0; - for (p = memmap_desc_start; - p < memmap_desc_end; - p += memmap_info->efi_memdesc_size) { - md = p; - - if (md_is_not_ram(md)) - continue; - - for (N = md->phys_addr >> PAGE_SHIFT; - N < (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >> - PAGE_SHIFT; - N++) { - if (!xc_ia64_p2m_allocated(p2m_table, N)) - pfntab[j++] = N; - if (j == sizeof(pfntab)/sizeof(pfntab[0])) { - if (write_exact(io_fd, &pfntab, sizeof(pfntab[0]) * j)) { - ERROR("Error when writing to state file (6b)"); - return -1; - } - j = 0; - } - } - } - if (j > 0) { - if (write_exact(io_fd, &pfntab, sizeof(pfntab[0]) * j)) { - ERROR("Error when writing to state file (6c)"); - return -1; - } - } - - return 0; -} - -static int -xc_ia64_send_vcpu_context(xc_interface *xch, int io_fd, uint32_t dom, - uint32_t vcpu, vcpu_guest_context_any_t *ctxt_any) -{ - vcpu_guest_context_t *ctxt = &ctxt_any->c; - if (xc_vcpu_getcontext(xch, dom, vcpu, ctxt_any)) { - ERROR("Could not get vcpu context"); - return -1; - } - - if (write_exact(io_fd, ctxt, sizeof(*ctxt))) { - ERROR("Error when writing to state file (1)"); - return -1; - } - - fprintf(stderr, "ip=%016lx, b0=%016lx\n", ctxt->regs.ip, ctxt->regs.b[0]); - return 0; -} - -static int -xc_ia64_send_shared_info(xc_interface *xch, int io_fd, shared_info_t *live_shinfo) -{ - if (write_exact(io_fd, live_shinfo, PAGE_SIZE)) { - ERROR("Error when writing to state file (1)"); - return -1; - } - return 0; -} - -static int -xc_ia64_send_vcpumap(xc_interface *xch, int io_fd, uint32_t dom, - const xc_dominfo_t *info, uint64_t max_virt_cpus, - uint64_t **vcpumapp) -{ - int rc = -1; - unsigned int i; - unsigned long vcpumap_size; - uint64_t *vcpumap = NULL; - - vcpumap_size = bitmap_size(max_virt_cpus); - vcpumap = bitmap_alloc(max_virt_cpus); - if (!vcpumap) { - ERROR("memory alloc for vcpumap"); - goto out; - } - - for (i = 0; i <= info->max_vcpu_id; i++) { - xc_vcpuinfo_t vinfo; - if ((xc_vcpu_getinfo(xch, dom, i, &vinfo) == 0) && vinfo.online) - set_bit(i, vcpumap); - } - - if (write_exact(io_fd, &max_virt_cpus, sizeof(max_virt_cpus))) { - ERROR("write max_virt_cpus"); - goto out; - } - - if (write_exact(io_fd, vcpumap, vcpumap_size)) { - ERROR("write vcpumap"); - goto out; - } - - rc = 0; - - out: - if (rc != 0 && vcpumap != NULL) { - free(vcpumap); - vcpumap = NULL; - } - *vcpumapp = vcpumap; - return rc; -} - - -static int -xc_ia64_pv_send_context(xc_interface *xch, int io_fd, uint32_t dom, - const xc_dominfo_t *info, shared_info_t *live_shinfo) -{ - int rc = -1; - unsigned int i; - - /* vcpu map */ - uint64_t *vcpumap = NULL; - if (xc_ia64_send_vcpumap(xch, io_fd, dom, info, XEN_LEGACY_MAX_VCPUS, - &vcpumap)) - goto out; - - /* vcpu context */ - for (i = 0; i <= info->max_vcpu_id; i++) { - /* A copy of the CPU context of the guest. */ - vcpu_guest_context_any_t ctxt_any; - vcpu_guest_context_t *ctxt = &ctxt_any.c; - - char *mem; - - if (!test_bit(i, vcpumap)) - continue; - - if (xc_ia64_send_vcpu_context(xch, io_fd, dom, i, &ctxt_any)) - goto out; - - mem = xc_map_foreign_range(xch, dom, PAGE_SIZE, - PROT_READ|PROT_WRITE, ctxt->privregs_pfn); - if (mem == NULL) { - ERROR("cannot map privreg page"); - goto out; - } - if (write_exact(io_fd, mem, PAGE_SIZE)) { - ERROR("Error when writing privreg to state file (5)"); - munmap(mem, PAGE_SIZE); - goto out; - } - munmap(mem, PAGE_SIZE); - } - - rc = xc_ia64_send_shared_info(xch, io_fd, live_shinfo); - - out: - if (vcpumap != NULL) - free(vcpumap); - return rc; -} - -static int -xc_ia64_hvm_send_context(xc_interface *xch, int io_fd, uint32_t dom, - const xc_dominfo_t *info, shared_info_t *live_shinfo) -{ - int rc = -1; - unsigned int i; - - /* vcpu map */ - uint64_t *vcpumap = NULL; - - /* HVM: magic frames for ioreqs and xenstore comms */ - const int hvm_params[] = { - HVM_PARAM_STORE_PFN, - HVM_PARAM_IOREQ_PFN, - HVM_PARAM_BUFIOREQ_PFN, - HVM_PARAM_BUFPIOREQ_PFN, - }; - const int NR_PARAMS = sizeof(hvm_params) / sizeof(hvm_params[0]); - /* ioreq_pfn, bufioreq_pfn, store_pfn */ - uint64_t magic_pfns[NR_PARAMS]; - - /* HVM: a buffer for holding HVM contxt */ - uint64_t rec_size; - uint64_t hvm_buf_size = 0; - uint8_t *hvm_buf = NULL; - - if (xc_ia64_send_shared_info(xch, io_fd, live_shinfo)) - return -1; - - /* vcpu map */ - if (xc_ia64_send_vcpumap(xch, io_fd, dom, info, XEN_LEGACY_MAX_VCPUS, - &vcpumap)) - goto out; - - /* vcpu context */ - for (i = 0; i <= info->max_vcpu_id; i++) { - /* A copy of the CPU context of the guest. */ - vcpu_guest_context_any_t ctxt_any; - - if (!test_bit(i, vcpumap)) - continue; - - if (xc_ia64_send_vcpu_context(xch, io_fd, dom, i, &ctxt_any)) - goto out; - - /* system context of vcpu is sent as hvm context. */ - } - - /* Save magic-page locations. */ - memset(magic_pfns, 0, sizeof(magic_pfns)); - for (i = 0; i < NR_PARAMS; i++) { - if (xc_get_hvm_param(xch, dom, hvm_params[i], &magic_pfns[i])) { - PERROR("Error when xc_get_hvm_param"); - goto out; - } - } - - if (write_exact(io_fd, magic_pfns, sizeof(magic_pfns))) { - ERROR("Error when writing to state file (7)"); - goto out; - } - - /* Need another buffer for HVM context */ - hvm_buf_size = xc_domain_hvm_getcontext(xch, dom, 0, 0); - if (hvm_buf_size == -1) { - ERROR("Couldn't get HVM context size from Xen"); - goto out; - } - - hvm_buf = malloc(hvm_buf_size); - if (!hvm_buf) { - ERROR("Couldn't allocate memory"); - goto out; - } - - /* Get HVM context from Xen and save it too */ - rec_size = xc_domain_hvm_getcontext(xch, dom, hvm_buf, hvm_buf_size); - if (rec_size == -1) { - ERROR("HVM:Could not get hvm buffer"); - goto out; - } - - if (write_exact(io_fd, &rec_size, sizeof(rec_size))) { - ERROR("error write hvm buffer size"); - goto out; - } - - if (write_exact(io_fd, hvm_buf, rec_size)) { - ERROR("write HVM info failed!\n"); - goto out; - } - - rc = 0; -out: - if (hvm_buf != NULL) - free(hvm_buf); - if (vcpumap != NULL) - free(vcpumap); - return rc; -} - -int -xc_domain_save(xc_interface *xch, int io_fd, uint32_t dom, uint32_t max_iters, - uint32_t max_factor, uint32_t flags, - struct save_callbacks* callbacks, int hvm, - unsigned long vm_generationid_addr) -{ - DECLARE_DOMCTL; - xc_dominfo_t info; - - int rc = 1; - - int debug = (flags & XCFLAGS_DEBUG); - int live = (flags & XCFLAGS_LIVE); - - /* The new domain's shared-info frame number. */ - unsigned long shared_info_frame; - - /* Live mapping of shared info structure */ - shared_info_t *live_shinfo = NULL; - - /* Iteration number. */ - int iter; - - /* Number of pages sent in the last iteration (live only). */ - unsigned int sent_last_iter; - - /* Number of pages sent (live only). */ - unsigned int total_sent = 0; - - /* total number of pages used by the current guest */ - unsigned long p2m_size; - - /* Size of the shadow bitmap (live only). */ - unsigned int bitmap_size = 0; - - /* True if last iteration. */ - int last_iter = 0; - - /* Bitmap of pages to be sent. */ - DECLARE_HYPERCALL_BUFFER(unsigned long, to_send); - /* Bitmap of pages not to be sent (because dirtied). */ - DECLARE_HYPERCALL_BUFFER(unsigned long, to_skip); - - char *mem; - - /* for foreign p2m exposure */ - unsigned long memmap_info_num_pages; - /* Unsigned int was used before. To keep file format compatibility. */ - unsigned int memmap_info_num_pages_to_send; - unsigned long memmap_size = 0; - xen_ia64_memmap_info_t *memmap_info = NULL; - void *memmap_desc_start; - void *memmap_desc_end; - void *p; - efi_memory_desc_t *md; - struct xen_ia64_p2m_table p2m_table; - - if ( hvm && !callbacks->switch_qemu_logdirty ) - { - ERROR("No switch_qemu_logdirty callback given."); - errno = EINVAL; - return 1; - } - - xc_ia64_p2m_init(&p2m_table); - - if (debug) - fprintf(stderr, "xc_linux_save (ia64): started dom=%d\n", dom); - - /* If no explicit control parameters given, use defaults */ - if (!max_iters) - max_iters = DEF_MAX_ITERS; - if (!max_factor) - max_factor = DEF_MAX_FACTOR; - - //initialize_mbit_rate(); - - if (xc_domain_getinfo(xch, dom, 1, &info) != 1) { - ERROR("Could not get domain info"); - return 1; - } - - shared_info_frame = info.shared_info_frame; - -#if 0 - /* cheesy sanity check */ - if ((info.max_memkb >> (PAGE_SHIFT - 10)) > max_mfn) { - ERROR("Invalid state record -- pfn count out of range: %lu", - (info.max_memkb >> (PAGE_SHIFT - 10))); - goto out; - } -#endif - - /* Map the shared info frame */ - live_shinfo = xc_map_foreign_range(xch, dom, PAGE_SIZE, - PROT_READ, shared_info_frame); - if (!live_shinfo) { - ERROR("Couldn't map live_shinfo"); - goto out; - } - - p2m_size = xc_domain_maximum_gpfn(xch, dom) + 1; - - /* This is expected by xm restore. */ - if (write_exact(io_fd, &p2m_size, sizeof(unsigned long))) { - ERROR("write: p2m_size"); - goto out; - } - - /* xc_linux_restore starts to read here. */ - /* Write a version number. This can avoid searching for a stupid bug - if the format change. - The version is hard-coded, don't forget to change the restore code - too! */ - { - unsigned long version = XC_IA64_SR_FORMAT_VER_CURRENT; - - if (write_exact(io_fd, &version, sizeof(unsigned long))) { - ERROR("write: version"); - goto out; - } - } - - domctl.cmd = XEN_DOMCTL_arch_setup; - domctl.domain = (domid_t)dom; - domctl.u.arch_setup.flags = XEN_DOMAINSETUP_query; - if (xc_domctl(xch, &domctl) < 0) { - ERROR("Could not get domain setup"); - goto out; - } - if (write_exact(io_fd, &domctl.u.arch_setup, - sizeof(domctl.u.arch_setup))) { - ERROR("write: domain setup"); - goto out; - } - - /* Domain is still running at this point */ - if (live) { - - if (xc_shadow_control(xch, dom, - XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY, - NULL, 0, NULL, 0, NULL ) < 0) { - ERROR("Couldn't enable shadow mode"); - goto out; - } - - last_iter = 0; - - bitmap_size = ((p2m_size + BITS_PER_LONG-1) & ~(BITS_PER_LONG-1)) / 8; - to_send = xc_hypercall_buffer_alloc(xch, to_send, bitmap_size); - to_skip = xc_hypercall_buffer_alloc(xch, to_skip, bitmap_size); - - if (!to_send || !to_skip) { - ERROR("Couldn't allocate bitmap array"); - goto out; - } - - /* Initially all the pages must be sent. */ - memset(to_send, 0xff, bitmap_size); - - /* Enable qemu-dm logging dirty pages to xen */ - if (hvm && callbacks->switch_qemu_logdirty(dom, 1, callbacks->data)) { - ERROR("Unable to enable qemu log-dirty mode"); - goto out; - } - } else { - - /* This is a non-live suspend. Issue the call back to get the - domain suspended */ - - last_iter = 1; - - if (suspend_and_state(callbacks->suspend, callbacks->data, xch, - io_fd, dom, &info)) { - ERROR("Domain appears not to have suspended"); - goto out; - } - - } - - /* copy before use in case someone updating them */ - if (xc_ia64_copy_memmap(xch, info.domid, live_shinfo, - &memmap_info, &memmap_info_num_pages) != 0) { - PERROR("Could not copy memmap"); - goto out; - } - memmap_size = memmap_info_num_pages << PAGE_SHIFT; - - if (xc_ia64_p2m_map(&p2m_table, xch, dom, memmap_info, 0) < 0) { - PERROR("xc_ia64_p2m_map"); - goto out; - } - memmap_info_num_pages_to_send = memmap_info_num_pages; - if (write_exact(io_fd, &memmap_info_num_pages_to_send, - sizeof(memmap_info_num_pages_to_send))) { - PERROR("write: arch.memmap_info_num_pages"); - goto out; - } - if (write_exact(io_fd, memmap_info, memmap_size)) { - PERROR("write: memmap_info"); - goto out; - } - - sent_last_iter = p2m_size; - - copypages: - for (iter = 1; ; iter++) { - unsigned int sent_this_iter, skip_this_iter; - unsigned long N; - - sent_this_iter = 0; - skip_this_iter = 0; - - /* Dirtied pages won't be saved. - slightly wasteful to peek the whole array evey time, - but this is fast enough for the moment. */ - if (!last_iter) { - if (xc_shadow_control(xch, dom, - XEN_DOMCTL_SHADOW_OP_PEEK, - HYPERCALL_BUFFER(to_skip), p2m_size, - NULL, 0, NULL) != p2m_size) { - ERROR("Error peeking shadow bitmap"); - goto out; - } - } - - /* Start writing out the saved-domain record. */ - memmap_desc_start = &memmap_info->memdesc; - memmap_desc_end = memmap_desc_start + memmap_info->efi_memmap_size; - for (p = memmap_desc_start; - p < memmap_desc_end; - p += memmap_info->efi_memdesc_size) { - md = p; - if (md_is_not_ram(md)) - continue; - - for (N = md->phys_addr >> PAGE_SHIFT; - N < (md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT)) >> - PAGE_SHIFT; - N++) { - - if (!xc_ia64_p2m_allocated(&p2m_table, N)) - continue; - - if (!last_iter) { - if (test_bit(N, to_skip) && test_bit(N, to_send)) - skip_this_iter++; - if (test_bit(N, to_skip) || !test_bit(N, to_send)) - continue; - } else if (live) { - if (!test_bit(N, to_send)) - continue; - } - - if (debug) - fprintf(stderr, "xc_linux_save: page %lx (%lu/%lu)\n", - xc_ia64_p2m_mfn(&p2m_table, N), - N, p2m_size); - - mem = xc_map_foreign_range(xch, dom, PAGE_SIZE, - PROT_READ|PROT_WRITE, N); - if (mem == NULL) { - /* The page may have move. - It will be remarked dirty. - FIXME: to be tracked. */ - fprintf(stderr, "cannot map mfn page %lx gpfn %lx: %s\n", - xc_ia64_p2m_mfn(&p2m_table, N), - N, xc_strerror(xch, errno)); - goto out; - } - - if (write_exact(io_fd, &N, sizeof(N))) { - ERROR("write: p2m_size"); - munmap(mem, PAGE_SIZE); - goto out; - } - - if (write(io_fd, mem, PAGE_SIZE) != PAGE_SIZE) { - ERROR("Error when writing to state file (5)"); - munmap(mem, PAGE_SIZE); - goto out; - } - munmap(mem, PAGE_SIZE); - sent_this_iter++; - total_sent++; - } - } - - if (last_iter) - break; - - DPRINTF(" %d: sent %d, skipped %d\n", - iter, sent_this_iter, skip_this_iter ); - - if (live) { - if ( /* ((sent_this_iter > sent_last_iter) && RATE_IS_MAX()) || */ - (iter >= max_iters) || (sent_this_iter+skip_this_iter < 50) || - (total_sent > p2m_size*max_factor)) { - DPRINTF("Start last iteration\n"); - last_iter = 1; - - if (suspend_and_state(callbacks->suspend, callbacks->data, - xch, io_fd, dom, &info)) { - ERROR("Domain appears not to have suspended"); - goto out; - } - } - - /* Pages to be sent are pages which were dirty. */ - if (xc_shadow_control(xch, dom, - XEN_DOMCTL_SHADOW_OP_CLEAN, - HYPERCALL_BUFFER(to_send), p2m_size, - NULL, 0, NULL ) != p2m_size) { - ERROR("Error flushing shadow PT"); - goto out; - } - - sent_last_iter = sent_this_iter; - - //print_stats(xch, dom, sent_this_iter, &stats, 1); - } - } - - fprintf(stderr, "All memory is saved\n"); - - /* terminate */ - { - unsigned long pfn = INVALID_MFN; - if (write_exact(io_fd, &pfn, sizeof(pfn))) { - ERROR("Error when writing to state file (6)"); - goto out; - } - } - - if (xc_ia64_send_unallocated_list(xch, io_fd, &p2m_table, - memmap_info, - memmap_desc_start, memmap_desc_end)) - goto out; - - if (!hvm) - rc = xc_ia64_pv_send_context(xch, io_fd, - dom, &info, live_shinfo); - else - rc = xc_ia64_hvm_send_context(xch, io_fd, - dom, &info, live_shinfo); - if (rc) - goto out; - - /* Success! */ - rc = 0; - - out: - if ( !rc && callbacks->postcopy ) - callbacks->postcopy(callbacks->data); - - /* Flush last write and discard cache for file. */ - discard_file_cache(xch, io_fd, 1 /* flush */); - - /* checkpoint_cb can spend arbitrarily long in between rounds */ - if (!rc && callbacks->checkpoint && - callbacks->checkpoint(callbacks->data) > 0) - { - /* reset stats timer */ - //print_stats(xch, dom, 0, &stats, 0); - - rc = 1; - /* last_iter = 1; */ - if ( suspend_and_state(callbacks->suspend, callbacks->data, xch, - io_fd, dom, &info) ) - { - ERROR("Domain appears not to have suspended"); - goto out; - } - DPRINTF("SUSPEND shinfo %08lx\n", info.shared_info_frame); - //print_stats(xch, dom, 0, &stats, 1); - - if ( xc_shadow_control(xch, dom, - XEN_DOMCTL_SHADOW_OP_CLEAN, HYPERCALL_BUFFER(to_send), - p2m_size, NULL, 0, NULL) != p2m_size ) - { - ERROR("Error flushing shadow PT"); - } - - goto copypages; - } - - if (live) { - if (xc_shadow_control(xch, dom, - XEN_DOMCTL_SHADOW_OP_OFF, - NULL, 0, NULL, 0, NULL ) < 0) { - DPRINTF("Warning - couldn't disable shadow mode"); - } - if ( hvm && - callbacks->switch_qemu_logdirty(dom, 0, callbacks->data) ) { - DPRINTF("Warning - couldn't disable qemu log-dirty mode"); - } - } - - xc_hypercall_buffer_free(xch, to_send); - xc_hypercall_buffer_free(xch, to_skip); - if (live_shinfo) - munmap(live_shinfo, PAGE_SIZE); - if (memmap_info) - free(memmap_info); - xc_ia64_p2m_unmap(&p2m_table); - - fprintf(stderr,"Save exit rc=%d\n",rc); - - return !!rc; -} - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ |