/* * Copyright (c) 2008, XenSource Inc. * All rights reserved. * * 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 XenSource Inc. 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 #include #include #include #include #include #include #include #include "libvhd.h" #include "tapdisk-image.h" #include "tapdisk-driver.h" #include "tapdisk-server.h" #include "tapdisk-interface.h" #include "tapdisk-vbd.h" #include "blktap2.h" #define DBG(_level, _f, _a...) tlog_write(_level, _f, ##_a) #define ERR(_err, _f, _a...) tlog_error(_err, _f, ##_a) #if 1 #define ASSERT(p) \ do { \ if (!(p)) { \ DPRINTF("Assertion '%s' failed, line %d, " \ "file %s", #p, __LINE__, __FILE__); \ *(int*)0 = 0; \ } \ } while (0) #else #define ASSERT(p) ((void)0) #endif #define TD_VBD_EIO_RETRIES 10 #define TD_VBD_EIO_SLEEP 1 #define TD_VBD_WATCHDOG_TIMEOUT 10 static void tapdisk_vbd_ring_event(event_id_t, char, void *); static void tapdisk_vbd_callback(void *, blkif_response_t *); /* * initialization */ static inline void tapdisk_vbd_initialize_vreq(td_vbd_request_t *vreq) { memset(vreq, 0, sizeof(td_vbd_request_t)); INIT_LIST_HEAD(&vreq->next); } int tapdisk_vbd_initialize(int rfd, int wfd, uint16_t uuid) { int i; td_vbd_t *vbd; vbd = tapdisk_server_get_vbd(uuid); if (vbd) { EPRINTF("duplicate vbds! %u\n", uuid); return -EEXIST; } vbd = calloc(1, sizeof(td_vbd_t)); if (!vbd) { EPRINTF("failed to allocate tapdisk state\n"); return -ENOMEM; } vbd->uuid = uuid; vbd->ipc.rfd = rfd; vbd->ipc.wfd = wfd; vbd->ipc.uuid = uuid; vbd->ring.fd = -1; /* default blktap ring completion */ vbd->callback = tapdisk_vbd_callback; vbd->argument = vbd; INIT_LIST_HEAD(&vbd->images); INIT_LIST_HEAD(&vbd->new_requests); INIT_LIST_HEAD(&vbd->pending_requests); INIT_LIST_HEAD(&vbd->failed_requests); INIT_LIST_HEAD(&vbd->completed_requests); INIT_LIST_HEAD(&vbd->next); gettimeofday(&vbd->ts, NULL); for (i = 0; i < MAX_REQUESTS; i++) tapdisk_vbd_initialize_vreq(vbd->request_list + i); tapdisk_server_add_vbd(vbd); return 0; } void tapdisk_vbd_set_callback(td_vbd_t *vbd, td_vbd_cb_t callback, void *argument) { vbd->callback = callback; vbd->argument = argument; } static int tapdisk_vbd_validate_chain(td_vbd_t *vbd) { int err; td_image_t *image, *parent, *tmp; DPRINTF("VBD CHAIN:\n"); tapdisk_vbd_for_each_image(vbd, image, tmp) { DPRINTF("%s: %d\n", image->name, image->type); if (tapdisk_vbd_is_last_image(vbd, image)) break; parent = tapdisk_vbd_next_image(image); err = td_validate_parent(image, parent); if (err) return err; } return 0; } void tapdisk_vbd_close_vdi(td_vbd_t *vbd) { td_image_t *image, *tmp; tapdisk_vbd_for_each_image(vbd, image, tmp) { td_close(image); tapdisk_image_free(image); } INIT_LIST_HEAD(&vbd->images); td_flag_set(vbd->state, TD_VBD_CLOSED); } static int tapdisk_vbd_add_block_cache(td_vbd_t *vbd) { int err; td_driver_t *driver; td_image_t *cache, *image, *target, *tmp; target = NULL; tapdisk_vbd_for_each_image(vbd, image, tmp) if (td_flag_test(image->flags, TD_OPEN_RDONLY) && td_flag_test(image->flags, TD_OPEN_SHAREABLE)) { target = image; break; } if (!target) return 0; cache = tapdisk_image_allocate(target->name, DISK_TYPE_BLOCK_CACHE, target->storage, target->flags, target->private); if (!cache) return -ENOMEM; /* try to load existing cache */ err = td_load(cache); if (!err) goto done; /* hack driver to send open() correct image size */ if (!target->driver) { err = -ENODEV; goto fail; } cache->driver = tapdisk_driver_allocate(cache->type, cache->name, cache->flags, cache->storage); if (!cache->driver) { err = -ENOMEM; goto fail; } cache->driver->info = target->driver->info; /* try to open new cache */ err = td_open(cache); if (!err) goto done; fail: /* give up */ tapdisk_image_free(target); return err; done: /* insert cache before image */ list_add(&cache->next, target->next.prev); return 0; } static int tapdisk_vbd_add_dirty_log(td_vbd_t *vbd) { int err; td_driver_t *driver; td_image_t *log, *parent; driver = NULL; log = NULL; parent = tapdisk_vbd_first_image(vbd); log = tapdisk_image_allocate(parent->name, DISK_TYPE_LOG, parent->storage, parent->flags, vbd); if (!log) return -ENOMEM; driver = tapdisk_driver_allocate(log->type, log->name, log->flags, log->storage); if (!driver) { err = -ENOMEM; goto fail; } driver->info = parent->driver->info; log->driver = driver; err = td_open(log); if (err) goto fail; list_add(&log->next, &vbd->images); return 0; fail: tapdisk_image_free(log); return err; } /* * LVHD hack: have to rescan LVM metadata on pool * slaves to register lvchanges made on master. FIXME. */ static int tapdisk_vbd_reactivate_volume(const char *name) { int err; char *cmd; DPRINTF("reactivating %s\n", name); err = asprintf(&cmd, "lvchange -an %s", name); if (err == - 1) { EPRINTF("failed to deactivate %s\n", name); return -errno; } err = system(cmd); if (err) { /* * Assume that LV deactivation failed because the LV is open, * in which case the LVM information should be up-to-date and * we don't need this step anyways (so ignore the error). If * the failure is due to a non-existent LV, the next command * (lvchange -ay) will catch it. * If we want to be more prudent/paranoid, we can instead check * whether the LV is currently open (a bit more work). */ } free(cmd); err = asprintf(&cmd, "lvchange -ay --refresh %s", name); if (err == - 1) { EPRINTF("failed to activate %s\n", name); return -errno; } err = system(cmd); if (err) EPRINTF("%s failed: %d\n", cmd, err); free(cmd); return err; } static int tapdisk_vbd_reactivate_volumes(td_vbd_t *vbd, int resume) { int i, cnt, err; char *name, *new; vhd_context_t vhd; vhd_parent_locator_t *loc; new = NULL; name = NULL; if (vbd->storage != TAPDISK_STORAGE_TYPE_LVM) return 0; if (!resume && vbd->reactivated) return 0; name = strdup(vbd->name); if (!name) { EPRINTF("%s: nomem\n", vbd->name); return -ENOMEM; } for (cnt = 0; 1; cnt++) { /* only need to reactivate child and parent during resume */ if (resume && cnt == 2) break; err = tapdisk_vbd_reactivate_volume(name); if (err) goto fail; if (!strstr(name, "VHD")) break; for (i = 0; i < TD_VBD_EIO_RETRIES; i++) { err = vhd_open(&vhd, name, VHD_OPEN_RDONLY); if (!err) break; libvhd_set_log_level(1); sleep(TD_VBD_EIO_SLEEP); } libvhd_set_log_level(0); if (err) goto fail; if (vhd.footer.type != HD_TYPE_DIFF) { vhd_close(&vhd); break; } loc = NULL; for (i = 0; i < 8; i++) if (vhd.header.loc[i].code == PLAT_CODE_MACX) { loc = vhd.header.loc + i; break; } if (!loc) { vhd_close(&vhd); err = -EINVAL; goto fail; } free(name); err = vhd_parent_locator_read(&vhd, loc, &name); vhd_close(&vhd); if (err) { name = NULL; goto fail; } /* * vhd_parent_locator_read returns path relative to child: * ./VG_XenStorage---VHD-- * we have to convert this to absolute path for lvm */ err = asprintf(&new, "/dev/mapper/%s", name + 2); if (err == -1) { err = -errno; goto fail; } free(name); name = new; } err = 0; vbd->reactivated = 1; out: free(name); return err; fail: EPRINTF("failed to reactivate %s: %d\n", vbd->name, err); goto out; } /* * LVHD hack: * raw volumes are named /dev/-/LV- * vhd volumes are named /dev/-/VHD- * * a live snapshot of a raw volume will result in the writeable volume's * name changing from the raw to vhd format, but this change will not be * reflected by xenstore. hence this mess. */ static int tapdisk_vbd_check_file(td_vbd_t *vbd) { int i, err; regex_t re; size_t len, max; regmatch_t matches[4]; char *new, *src, *dst, error[256]; if (vbd->storage != TAPDISK_STORAGE_TYPE_LVM) return 0; err = tapdisk_vbd_reactivate_volume(vbd->name); if (!err) return 0; else DPRINTF("reactivating %s failed\n", vbd->name); #define HEX "[A-Za-z0-9]" #define UUID HEX"\\{8\\}-"HEX"\\{4\\}-"HEX"\\{4\\}-"HEX"\\{4\\}-"HEX"\\{12\\}" #define VG "VG_"HEX"\\+" #define TYPE "\\(LV\\|VHD\\)" #define RE "\\(/dev/"VG"-"UUID"/\\)"TYPE"\\(-"UUID"\\)" err = regcomp(&re, RE, 0); if (err) goto regerr; #undef HEX #undef UUID #undef VG #undef TYPE #undef RE err = regexec(&re, vbd->name, 4, matches, 0); if (err) goto regerr; max = strlen("VHD") + 1; for (i = 1; i < 4; i++) { if (matches[i].rm_so == -1 || matches[i].rm_eo == -1) { EPRINTF("%s: failed to tokenize name\n", vbd->name); err = -EINVAL; goto out; } max += matches[i].rm_eo - matches[i].rm_so; } new = malloc(max); if (!new) { EPRINTF("%s: failed to allocate new name\n", vbd->name); err = -ENOMEM; goto out; } src = new; for (i = 1; i < 4; i++) { dst = vbd->name + matches[i].rm_so; len = matches[i].rm_eo - matches[i].rm_so; if (i == 2) { if (memcmp(dst, "LV", len)) { EPRINTF("%s: bad name format\n", vbd->name); free(new); err = -EINVAL; goto out; } src += sprintf(src, "VHD"); continue; } memcpy(src, dst, len + 1); src += len; } *src = '\0'; err = tapdisk_vbd_reactivate_volume(new); if (err) DPRINTF("reactivating %s failed\n", new); err = access(new, F_OK); if (err == -1) { EPRINTF("neither %s nor %s accessible\n", vbd->name, new); err = -errno; free(new); goto out; } DPRINTF("couldn't find %s, trying %s\n", vbd->name, new); err = 0; free(vbd->name); vbd->name = new; vbd->type = DISK_TYPE_VHD; out: regfree(&re); return err; regerr: regerror(err, &re, error, sizeof(error)); EPRINTF("%s: regex failed: %s\n", vbd->name, error); err = -EINVAL; goto out; } static int __tapdisk_vbd_open_vdi(td_vbd_t *vbd, td_flag_t extra_flags) { char *file; int err, type; td_flag_t flags; td_disk_id_t id; td_image_t *image, *tmp; struct tfilter *filter = NULL; err = tapdisk_vbd_reactivate_volumes(vbd, 0); if (err) return err; flags = (vbd->flags & ~TD_OPEN_SHAREABLE) | extra_flags; file = vbd->name; type = vbd->type; for (;;) { err = -ENOMEM; image = tapdisk_image_allocate(file, type, vbd->storage, flags, vbd); if (file != vbd->name) { free(file); file = NULL; } if (!image) goto fail; err = td_load(image); if (err) { if (err != -ENODEV) goto fail; err = td_open(image); if (err) goto fail; } err = td_get_parent_id(image, &id); if (err && err != TD_NO_PARENT) { td_close(image); goto fail; } if (!image->storage) image->storage = vbd->storage; tapdisk_vbd_add_image(vbd, image); image = NULL; if (err == TD_NO_PARENT) break; file = id.name; type = id.drivertype; flags |= (TD_OPEN_RDONLY | TD_OPEN_SHAREABLE); } if (td_flag_test(vbd->flags, TD_OPEN_LOG_DIRTY)) { err = tapdisk_vbd_add_dirty_log(vbd); if (err) goto fail; } if (td_flag_test(vbd->flags, TD_OPEN_ADD_CACHE)) { err = tapdisk_vbd_add_block_cache(vbd); if (err) goto fail; } err = tapdisk_vbd_validate_chain(vbd); if (err) goto fail; td_flag_clear(vbd->state, TD_VBD_CLOSED); return 0; fail: if (image) tapdisk_image_free(image); tapdisk_vbd_close_vdi(vbd); return err; } int tapdisk_vbd_open_vdi(td_vbd_t *vbd, const char *path, uint16_t drivertype, uint16_t storage, td_flag_t flags) { int i, err; struct tap_disk *ops; ops = tapdisk_server_find_driver_interface(drivertype); if (!ops) return -EINVAL; DPRINTF("Loaded %s driver for vbd %u %s 0x%08x\n", ops->disk_type, vbd->uuid, path, flags); err = tapdisk_namedup(&vbd->name, path); if (err) return err; vbd->flags = flags; vbd->storage = storage; vbd->type = drivertype; for (i = 0; i < TD_VBD_EIO_RETRIES; i++) { err = __tapdisk_vbd_open_vdi(vbd, 0); if (err != -EIO) break; sleep(TD_VBD_EIO_SLEEP); } if (err) goto fail; return 0; fail: free(vbd->name); vbd->name = NULL; return err; } static int tapdisk_vbd_register_event_watches(td_vbd_t *vbd) { event_id_t id; id = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD, vbd->ring.fd, 0, tapdisk_vbd_ring_event, vbd); if (id < 0) return id; vbd->ring_event_id = id; return 0; } static void tapdisk_vbd_unregister_events(td_vbd_t *vbd) { if (vbd->ring_event_id) tapdisk_server_unregister_event(vbd->ring_event_id); } static int tapdisk_vbd_map_device(td_vbd_t *vbd, const char *devname) { int err, psize; td_ring_t *ring; ring = &vbd->ring; psize = getpagesize(); ring->fd = open(devname, O_RDWR); if (ring->fd == -1) { err = -errno; EPRINTF("failed to open %s: %d\n", devname, err); goto fail; } ring->mem = mmap(0, psize * BLKTAP_MMAP_REGION_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, ring->fd, 0); if (ring->mem == MAP_FAILED) { err = -errno; EPRINTF("failed to mmap %s: %d\n", devname, err); goto fail; } ring->sring = (blkif_sring_t *)((unsigned long)ring->mem); BACK_RING_INIT(&ring->fe_ring, ring->sring, psize); ring->vstart = (unsigned long)ring->mem + (BLKTAP_RING_PAGES * psize); ioctl(ring->fd, BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_INTERPOSE); return 0; fail: if (ring->mem && ring->mem != MAP_FAILED) munmap(ring->mem, psize * BLKTAP_MMAP_REGION_SIZE); if (ring->fd != -1) close(ring->fd); ring->fd = -1; ring->mem = NULL; return err; } static int tapdisk_vbd_unmap_device(td_vbd_t *vbd) { int psize; psize = getpagesize(); if (vbd->ring.fd != -1) close(vbd->ring.fd); if (vbd->ring.mem > 0) munmap(vbd->ring.mem, psize * BLKTAP_MMAP_REGION_SIZE); return 0; } int tapdisk_vbd_open(td_vbd_t *vbd, const char *name, uint16_t type, uint16_t storage, const char *ring, td_flag_t flags) { int err; err = tapdisk_vbd_open_vdi(vbd, name, type, storage, flags); if (err) goto out; err = tapdisk_vbd_map_device(vbd, ring); if (err) goto out; err = tapdisk_vbd_register_event_watches(vbd); if (err) goto out; return 0; out: tapdisk_vbd_close_vdi(vbd); tapdisk_vbd_unmap_device(vbd); tapdisk_vbd_unregister_events(vbd); free(vbd->name); vbd->name = NULL; return err; } static void tapdisk_vbd_queue_count(td_vbd_t *vbd, int *new, int *pending, int *failed, int *completed) { int n, p, f, c; td_vbd_request_t *vreq, *tvreq; n = 0; p = 0; f = 0; c = 0; tapdisk_vbd_for_each_request(vreq, tvreq, &vbd->new_requests) n++; tapdisk_vbd_for_each_request(vreq, tvreq, &vbd->pending_requests) p++; tapdisk_vbd_for_each_request(vreq, tvreq, &vbd->failed_requests) f++; tapdisk_vbd_for_each_request(vreq, tvreq, &vbd->completed_requests) c++; *new = n; *pending = p; *failed = f; *completed = c; } static int tapdisk_vbd_shutdown(td_vbd_t *vbd) { int new, pending, failed, completed; if (!list_empty(&vbd->pending_requests)) return -EAGAIN; tapdisk_vbd_kick(vbd); tapdisk_vbd_queue_count(vbd, &new, &pending, &failed, &completed); DPRINTF("%s: state: 0x%08x, new: 0x%02x, pending: 0x%02x, " "failed: 0x%02x, completed: 0x%02x\n", vbd->name, vbd->state, new, pending, failed, completed); DPRINTF("last activity: %010ld.%06ld, errors: 0x%04"PRIx64", " "retries: 0x%04"PRIx64", received: 0x%08"PRIx64", " "returned: 0x%08"PRIx64", kicked: 0x%08"PRIx64"\n", vbd->ts.tv_sec, vbd->ts.tv_usec, vbd->errors, vbd->retries, vbd->received, vbd->returned, vbd->kicked); tapdisk_vbd_close_vdi(vbd); tapdisk_ipc_write(&vbd->ipc, TAPDISK_MESSAGE_CLOSE_RSP); tapdisk_vbd_unregister_events(vbd); tapdisk_vbd_unmap_device(vbd); tapdisk_server_remove_vbd(vbd); free(vbd->name); free(vbd); tlog_print_errors(); return 0; } int tapdisk_vbd_close(td_vbd_t *vbd) { /* * don't close if any requests are pending in the aio layer */ if (!list_empty(&vbd->pending_requests)) goto fail; /* * if the queue is still active and we have more * requests, try to complete them before closing. */ if (tapdisk_vbd_queue_ready(vbd) && (!list_empty(&vbd->new_requests) || !list_empty(&vbd->failed_requests) || !list_empty(&vbd->completed_requests))) goto fail; return tapdisk_vbd_shutdown(vbd); fail: td_flag_set(vbd->state, TD_VBD_SHUTDOWN_REQUESTED); DBG(TLOG_WARN, "%s: requests pending\n", vbd->name); return -EAGAIN; } /* * control operations */ void tapdisk_vbd_debug(td_vbd_t *vbd) { td_image_t *image, *tmp; int new, pending, failed, completed; tapdisk_vbd_queue_count(vbd, &new, &pending, &failed, &completed); DBG(TLOG_WARN, "%s: state: 0x%08x, new: 0x%02x, pending: 0x%02x, " "failed: 0x%02x, completed: 0x%02x, last activity: %010ld.%06ld, " "errors: 0x%04"PRIx64", retries: 0x%04"PRIx64", received: 0x%08"PRIx64", " "returned: 0x%08"PRIx64", kicked: 0x%08"PRIx64"\n", vbd->name, vbd->state, new, pending, failed, completed, vbd->ts.tv_sec, vbd->ts.tv_usec, vbd->errors, vbd->retries, vbd->received, vbd->returned, vbd->kicked); tapdisk_vbd_for_each_image(vbd, image, tmp) td_debug(image); } static void tapdisk_vbd_drop_log(td_vbd_t *vbd) { if (td_flag_test(vbd->state, TD_VBD_LOG_DROPPED)) return; tapdisk_vbd_debug(vbd); tlog_flush(); td_flag_set(vbd->state, TD_VBD_LOG_DROPPED); } int tapdisk_vbd_get_image_info(td_vbd_t *vbd, image_t *img) { td_image_t *image; memset(img, 0, sizeof(image_t)); if (list_empty(&vbd->images)) return -EINVAL; image = tapdisk_vbd_first_image(vbd); img->size = image->info.size; img->secsize = image->info.sector_size; img->info = image->info.info; return 0; } int tapdisk_vbd_queue_ready(td_vbd_t *vbd) { return (!td_flag_test(vbd->state, TD_VBD_DEAD) && !td_flag_test(vbd->state, TD_VBD_CLOSED) && !td_flag_test(vbd->state, TD_VBD_QUIESCED) && !td_flag_test(vbd->state, TD_VBD_QUIESCE_REQUESTED)); } int tapdisk_vbd_retry_needed(td_vbd_t *vbd) { return td_flag_test(vbd->state, TD_VBD_RETRY_NEEDED); } int tapdisk_vbd_lock(td_vbd_t *vbd) { return 0; } int tapdisk_vbd_quiesce_queue(td_vbd_t *vbd) { if (!list_empty(&vbd->pending_requests)) { td_flag_set(vbd->state, TD_VBD_QUIESCE_REQUESTED); return -EAGAIN; } td_flag_clear(vbd->state, TD_VBD_QUIESCE_REQUESTED); td_flag_set(vbd->state, TD_VBD_QUIESCED); return 0; } int tapdisk_vbd_start_queue(td_vbd_t *vbd) { td_flag_clear(vbd->state, TD_VBD_QUIESCED); td_flag_clear(vbd->state, TD_VBD_QUIESCE_REQUESTED); return 0; } int tapdisk_vbd_kill_queue(td_vbd_t *vbd) { tapdisk_vbd_quiesce_queue(vbd); td_flag_set(vbd->state, TD_VBD_DEAD); return 0; } static int tapdisk_vbd_open_image(td_vbd_t *vbd, td_image_t *image) { int err; td_image_t *parent; err = td_open(image); if (err) return err; if (!tapdisk_vbd_is_last_image(vbd, image)) { parent = tapdisk_vbd_next_image(image); err = td_validate_parent(image, parent); if (err) { td_close(image); return err; } } return 0; } static int tapdisk_vbd_close_and_reopen_image(td_vbd_t *vbd, td_image_t *image) { int i, err; td_close(image); for (i = 0; i < TD_VBD_EIO_RETRIES; i++) { err = tapdisk_vbd_open_image(vbd, image); if (err != -EIO) break; sleep(TD_VBD_EIO_SLEEP); } if (err) td_flag_set(vbd->state, TD_VBD_CLOSED); return err; } int tapdisk_vbd_pause(td_vbd_t *vbd) { int err; td_flag_set(vbd->state, TD_VBD_PAUSE_REQUESTED); err = tapdisk_vbd_quiesce_queue(vbd); if (err) return err; tapdisk_vbd_close_vdi(vbd); td_flag_clear(vbd->state, TD_VBD_PAUSE_REQUESTED); td_flag_set(vbd->state, TD_VBD_PAUSED); tapdisk_ipc_write(&vbd->ipc, TAPDISK_MESSAGE_PAUSE_RSP); return 0; } int tapdisk_vbd_resume(td_vbd_t *vbd, const char *path, uint16_t drivertype) { int i, err; if (!td_flag_test(vbd->state, TD_VBD_PAUSED)) { EPRINTF("resume request for unpaused vbd %s\n", vbd->name); tapdisk_ipc_write(&vbd->ipc, TAPDISK_MESSAGE_ERROR); return -EINVAL; } free(vbd->name); vbd->name = strdup(path); if (!vbd->name) { EPRINTF("copying new vbd %s name failed\n", path); tapdisk_ipc_write(&vbd->ipc, TAPDISK_MESSAGE_ERROR); return -EINVAL; } vbd->type = drivertype; for (i = 0; i < TD_VBD_EIO_RETRIES; i++) { err = tapdisk_vbd_check_file(vbd); if (err) goto sleep; err = tapdisk_vbd_reactivate_volumes(vbd, 1); if (err) { EPRINTF("failed to reactivate %s: %d\n", vbd->name, err); goto sleep; } err = __tapdisk_vbd_open_vdi(vbd, TD_OPEN_STRICT); if (!err) break; sleep: sleep(TD_VBD_EIO_SLEEP); } if (err) { tapdisk_ipc_write(&vbd->ipc, TAPDISK_MESSAGE_ERROR); return err; } tapdisk_vbd_start_queue(vbd); td_flag_clear(vbd->state, TD_VBD_PAUSED); td_flag_clear(vbd->state, TD_VBD_PAUSE_REQUESTED); tapdisk_ipc_write(&vbd->ipc, TAPDISK_MESSAGE_RESUME_RSP); return 0; } int tapdisk_vbd_kick(td_vbd_t *vbd) { int n; td_ring_t *ring; ring = &vbd->ring; if (!ring->sring) return 0; n = (ring->fe_ring.rsp_prod_pvt - ring->fe_ring.sring->rsp_prod); if (!n) return 0; vbd->kicked += n; RING_PUSH_RESPONSES(&ring->fe_ring); ioctl(ring->fd, BLKTAP_IOCTL_KICK_FE, 0); DBG(TLOG_INFO, "kicking %d: rec: 0x%08"PRIx64", ret: 0x%08"PRIx64", kicked: " "0x%08"PRIx64"\n", n, vbd->received, vbd->returned, vbd->kicked); return n; } static inline void tapdisk_vbd_write_response_to_ring(td_vbd_t *vbd, blkif_response_t *rsp) { td_ring_t *ring; blkif_response_t *rspp; ring = &vbd->ring; rspp = RING_GET_RESPONSE(&ring->fe_ring, ring->fe_ring.rsp_prod_pvt); memcpy(rspp, rsp, sizeof(blkif_response_t)); ring->fe_ring.rsp_prod_pvt++; } static void tapdisk_vbd_callback(void *arg, blkif_response_t *rsp) { td_vbd_t *vbd = (td_vbd_t *)arg; tapdisk_vbd_write_response_to_ring(vbd, rsp); } static void tapdisk_vbd_make_response(td_vbd_t *vbd, td_vbd_request_t *vreq) { blkif_request_t tmp; blkif_response_t *rsp; tmp = vreq->req; rsp = (blkif_response_t *)&vreq->req; rsp->id = tmp.id; rsp->operation = tmp.operation; rsp->status = vreq->status; DBG(TLOG_DBG, "writing req %d, sec 0x%08"PRIx64", res %d to ring\n", (int)tmp.id, tmp.sector_number, vreq->status); if (rsp->status != BLKIF_RSP_OKAY) ERR(EIO, "returning BLKIF_RSP %d", rsp->status); vbd->returned++; vbd->callback(vbd->argument, rsp); } void tapdisk_vbd_check_state(td_vbd_t *vbd) { td_vbd_request_t *vreq, *tmp; tapdisk_vbd_for_each_request(vreq, tmp, &vbd->failed_requests) if (vreq->num_retries >= TD_VBD_MAX_RETRIES) tapdisk_vbd_complete_vbd_request(vbd, vreq); if (!list_empty(&vbd->new_requests) || !list_empty(&vbd->failed_requests)) tapdisk_vbd_issue_requests(vbd); tapdisk_vbd_for_each_request(vreq, tmp, &vbd->completed_requests) { tapdisk_vbd_make_response(vbd, vreq); list_del(&vreq->next); tapdisk_vbd_initialize_vreq(vreq); } if (td_flag_test(vbd->state, TD_VBD_QUIESCE_REQUESTED)) tapdisk_vbd_quiesce_queue(vbd); if (td_flag_test(vbd->state, TD_VBD_PAUSE_REQUESTED)) tapdisk_vbd_pause(vbd); if (td_flag_test(vbd->state, TD_VBD_SHUTDOWN_REQUESTED)) tapdisk_vbd_close(vbd); } void tapdisk_vbd_check_progress(td_vbd_t *vbd) { int diff; struct timeval now; if (list_empty(&vbd->pending_requests)) return; get
Please send your questions to the
[googlemock](http://groups.google.com/group/googlemock) discussion
group. If you need help with compiler errors, make sure you have
tried [Google Mock Doctor](#How_am_I_supposed_to_make_sense_of_these_horrible_template_error.md) first.

## When I call a method on my mock object, the method for the real object is invoked instead.  What's the problem? ##

In order for a method to be mocked, it must be _virtual_, unless you use the [high-perf dependency injection technique](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Mocking_Nonvirtual_Methods).

## I wrote some matchers.  After I upgraded to a new version of Google Mock, they no longer compile.  What's going on? ##

After version 1.4.0 of Google Mock was released, we had an idea on how
to make it easier to write matchers that can generate informative
messages efficiently.  We experimented with this idea and liked what
we saw.  Therefore we decided to implement it.

Unfortunately, this means that if you have defined your own matchers
by implementing `MatcherInterface` or using `MakePolymorphicMatcher()`,
your definitions will no longer compile.  Matchers defined using the
`MATCHER*` family of macros are not affected.

Sorry for the hassle if your matchers are affected.  We believe it's
in everyone's long-term interest to make this change sooner than
later.  Fortunately, it's usually not hard to migrate an existing
matcher to the new API.  Here's what you need to do:

If you wrote your matcher like this:
```
// Old matcher definition that doesn't work with the latest
// Google Mock.
using ::testing::MatcherInterface;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
 public:
  ...
  virtual bool Matches(MyType value) const {
    // Returns true if value matches.
    return value.GetFoo() > 5;
  }
  ...
};
```

you'll need to change it to:
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MatcherInterface;
using ::testing::MatchResultListener;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
 public:
  ...
  virtual bool MatchAndExplain(MyType value,
                               MatchResultListener* listener) const {
    // Returns true if value matches.
    return value.GetFoo() > 5;
  }
  ...
};
```
(i.e. rename `Matches()` to `MatchAndExplain()` and give it a second
argument of type `MatchResultListener*`.)

If you were also using `ExplainMatchResultTo()` to improve the matcher
message:
```
// Old matcher definition that doesn't work with the lastest
// Google Mock.
using ::testing::MatcherInterface;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
 public:
  ...
  virtual bool Matches(MyType value) const {
    // Returns true if value matches.
    return value.GetFoo() > 5;
  }

  virtual void ExplainMatchResultTo(MyType value,
                                    ::std::ostream* os) const {
    // Prints some helpful information to os to help
    // a user understand why value matches (or doesn't match).
    *os << "the Foo property is " << value.GetFoo();
  }
  ...
};
```

you should move the logic of `ExplainMatchResultTo()` into
`MatchAndExplain()`, using the `MatchResultListener` argument where
the `::std::ostream` was used:
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MatcherInterface;
using ::testing::MatchResultListener;
...
class MyWonderfulMatcher : public MatcherInterface<MyType> {
 public:
  ...
  virtual bool MatchAndExplain(MyType value,
                               MatchResultListener* listener) const {
    // Returns true if value matches.
    *listener << "the Foo property is " << value.GetFoo();
    return value.GetFoo() > 5;
  }
  ...
};
```

If your matcher is defined using `MakePolymorphicMatcher()`:
```
// Old matcher definition that doesn't work with the latest
// Google Mock.
using ::testing::MakePolymorphicMatcher;
...
class MyGreatMatcher {
 public:
  ...
  bool Matches(MyType value) const {
    // Returns true if value matches.
    return value.GetBar() < 42;
  }
  ...
};
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```

you should rename the `Matches()` method to `MatchAndExplain()` and
add a `MatchResultListener*` argument (the same as what you need to do
for matchers defined by implementing `MatcherInterface`):
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MakePolymorphicMatcher;
using ::testing::MatchResultListener;
...
class MyGreatMatcher {
 public:
  ...
  bool MatchAndExplain(MyType value,
                       MatchResultListener* listener) const {
    // Returns true if value matches.
    return value.GetBar() < 42;
  }
  ...
};
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```

If your polymorphic matcher uses `ExplainMatchResultTo()` for better
failure messages:
```
// Old matcher definition that doesn't work with the latest
// Google Mock.
using ::testing::MakePolymorphicMatcher;
...
class MyGreatMatcher {
 public:
  ...
  bool Matches(MyType value) const {
    // Returns true if value matches.
    return value.GetBar() < 42;
  }
  ...
};
void ExplainMatchResultTo(const MyGreatMatcher& matcher,
                          MyType value,
                          ::std::ostream* os) {
  // Prints some helpful information to os to help
  // a user understand why value matches (or doesn't match).
  *os << "the Bar property is " << value.GetBar();
}
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```

you'll need to move the logic inside `ExplainMatchResultTo()` to
`MatchAndExplain()`:
```
// New matcher definition that works with the latest Google Mock.
using ::testing::MakePolymorphicMatcher;
using ::testing::MatchResultListener;
...
class MyGreatMatcher {
 public:
  ...
  bool MatchAndExplain(MyType value,
                       MatchResultListener* listener) const {
    // Returns true if value matches.
    *listener << "the Bar property is " << value.GetBar();
    return value.GetBar() < 42;
  }
  ...
};
... MakePolymorphicMatcher(MyGreatMatcher()) ...
```

For more information, you can read these
[two](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Monomorphic_Matchers)
[recipes](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Polymorphic_Matchers)
from the cookbook.  As always, you
are welcome to post questions on `googlemock@googlegroups.com` if you
need any help.

## When using Google Mock, do I have to use Google Test as the testing framework?  I have my favorite testing framework and don't want to switch. ##

Google Mock works out of the box with Google Test.  However, it's easy
to configure it to work with any testing framework of your choice.
[Here](http://code.google.com/p/googlemock/wiki/V1_7_ForDummies#Using_Google_Mock_with_Any_Testing_Framework) is how.

## How am I supposed to make sense of these horrible template errors? ##

If you are confused by the compiler errors gcc threw at you,
try consulting the _Google Mock Doctor_ tool first.  What it does is to
scan stdin for gcc error messages, and spit out diagnoses on the
problems (we call them diseases) your code has.

To "install", run command:
```
alias gmd='<path to googlemock>/scripts/gmock_doctor.py'
```

To use it, do:
```
<your-favorite-build-command> <your-test> 2>&1 | gmd
```

For example:
```
make my_test 2>&1 | gmd
```

Or you can run `gmd` and copy-n-paste gcc's error messages to it.

## Can I mock a variadic function? ##

You cannot mock a variadic function (i.e. a function taking ellipsis
(`...`) arguments) directly in Google Mock.

The problem is that in general, there is _no way_ for a mock object to
know how many arguments are passed to the variadic method, and what
the arguments' types are.  Only the _author of the base class_ knows
the protocol, and we cannot look into his head.

Therefore, to mock such a function, the _user_ must teach the mock
object how to figure out the number of arguments and their types.  One
way to do it is to provide overloaded versions of the function.

Ellipsis arguments are inherited from C and not really a C++ feature.
They are unsafe to use and don't work with arguments that have
constructors or destructors.  Therefore we recommend to avoid them in
C++ as much as possible.

## MSVC gives me warning C4301 or C4373 when I define a mock method with a const parameter.  Why? ##

If you compile this using Microsoft Visual C++ 2005 SP1:
```
class Foo {
  ...
  virtual void Bar(const int i) = 0;
};

class MockFoo : public Foo {
  ...
  MOCK_METHOD1(Bar, void(const int i));
};
```
You may get the following warning:
```
warning C4301: 'MockFoo::Bar': overriding virtual function only differs from 'Foo::Bar' by const/volatile qualifier
```

This is a MSVC bug.  The same code compiles fine with gcc ,for
example.  If you use Visual C++ 2008 SP1, you would get the warning:
```
warning C4373: 'MockFoo::Bar': virtual function overrides 'Foo::Bar', previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers
```

In C++, if you _declare_ a function with a `const` parameter, the
`const` modifier is _ignored_.  Therefore, the `Foo` base class above
is equivalent to:
```
class Foo {
  ...
  virtual void Bar(int i) = 0;  // int or const int?  Makes no difference.
};
```

In fact, you can _declare_ Bar() with an `int` parameter, and _define_
it with a `const int` parameter.  The compiler will still match them
up.

Since making a parameter `const` is meaningless in the method
_declaration_, we recommend to remove it in both `Foo` and `MockFoo`.
That should workaround the VC bug.

Note that we are talking about the _top-level_ `const` modifier here.
If the function parameter is passed by pointer or reference, declaring
the _pointee_ or _referee_ as `const` is still meaningful.  For
example, the following two declarations are _not_ equivalent:
```
void Bar(int* p);        // Neither p nor *p is const.
void Bar(const int* p);  // p is not const, but *p is.
```

## I have a huge mock class, and Microsoft Visual C++ runs out of memory when compiling it.  What can I do? ##

We've noticed that when the `/clr` compiler flag is used, Visual C++
uses 5~6 times as much memory when compiling a mock class.  We suggest
to avoid `/clr` when compiling native C++ mocks.

## I can't figure out why Google Mock thinks my expectations are not satisfied.  What should I do? ##

You might want to run your test with
`--gmock_verbose=info`.  This flag lets Google Mock print a trace
of every mock function call it receives.  By studying the trace,
you'll gain insights on why the expectations you set are not met.

## How can I assert that a function is NEVER called? ##

```
EXPECT_CALL(foo, Bar(_))
    .Times(0);
```

## I have a failed test where Google Mock tells me TWICE that a particular expectation is not satisfied.  Isn't this redundant? ##

When Google Mock detects a failure, it prints relevant information
(the mock function arguments, the state of relevant expectations, and
etc) to help the user debug.  If another failure is detected, Google
Mock will do the same, including printing the state of relevant
expectations.

Sometimes an expectation's state didn't change between two failures,
and you'll see the same description of the state twice.  They are
however _not_ redundant, as they refer to _different points in time_.
The fact they are the same _is_ interesting information.

## I get a heap check failure when using a mock object, but using a real object is fine.  What can be wrong? ##

Does the class (hopefully a pure interface) you are mocking have a
virtual destructor?

Whenever you derive from a base class, make sure its destructor is
virtual.  Otherwise Bad Things will happen.  Consider the following
code:

```
class Base {
 public:
  // Not virtual, but should be.
  ~Base() { ... }
  ...
};

class Derived : public Base {
 public:
  ...
 private:
  std::string value_;
};

...
  Base* p = new Derived;
  ...
  delete p;  // Surprise! ~Base() will be called, but ~Derived() will not
             // - value_ is leaked.
```

By changing `~Base()` to virtual, `~Derived()` will be correctly
called when `delete p` is executed, and the heap checker
will be happy.

## The "newer expectations override older ones" rule makes writing expectations awkward.  Why does Google Mock do that? ##

When people complain about this, often they are referring to code like:

```
// foo.Bar() should be called twice, return 1 the first time, and return
// 2 the second time.  However, I have to write the expectations in the
// reverse order.  This sucks big time!!!
EXPECT_CALL(foo, Bar())
    .WillOnce(Return(2))
    .RetiresOnSaturation();
EXPECT_CALL(foo, Bar())
    .WillOnce(Return(1))
    .RetiresOnSaturation();
```

The problem is that they didn't pick the **best** way to express the test's
intent.

By default, expectations don't have to be matched in _any_ particular
order.  If you want them to match in a certain order, you need to be
explicit.  This is Google Mock's (and jMock's) fundamental philosophy: it's
easy to accidentally over-specify your tests, and we want to make it
harder to do so.

There are two better ways to write the test spec.  You could either
put the expectations in sequence:

```
// foo.Bar() should be called twice, return 1 the first time, and return
// 2 the second time.  Using a sequence, we can write the expectations
// in their natural order.
{
  InSequence s;
  EXPECT_CALL(foo, Bar())
      .WillOnce(Return(1))
      .RetiresOnSaturation();
  EXPECT_CALL(foo, Bar())
      .WillOnce(Return(2))
      .RetiresOnSaturation();
}
```

or you can put the sequence of actions in the same expectation:

```
// foo.Bar() should be called twice, return 1 the first time, and return
// 2 the second time.
EXPECT_CALL(foo, Bar())
    .WillOnce(Return(1))
    .WillOnce(Return(2))
    .RetiresOnSaturation();
```

Back to the original questions: why does Google Mock search the
expectations (and `ON_CALL`s) from back to front?  Because this
allows a user to set up a mock's behavior for the common case early
(e.g. in the mock's constructor or the test fixture's set-up phase)
and customize it with more specific rules later.  If Google Mock
searches from front to back, this very useful pattern won't be
possible.

## Google Mock prints a warning when a function without EXPECT\_CALL is called, even if I have set its behavior using ON\_CALL.  Would it be reasonable not to show the warning in this case? ##

When choosing between being neat and being safe, we lean toward the
latter.  So the answer is that we think it's better to show the
warning.

Often people write `ON_CALL`s in the mock object's
constructor or `SetUp()`, as the default behavior rarely changes from
test to test.  Then in the test body they set the expectations, which
are often different for each test.  Having an `ON_CALL` in the set-up
part of a test doesn't mean that the calls are expected.  If there's
no `EXPECT_CALL` and the method is called, it's possibly an error.  If
we quietly let the call go through without notifying the user, bugs
may creep in unnoticed.

If, however, you are sure that the calls are OK, you can write

```
EXPECT_CALL(foo, Bar(_))
    .WillRepeatedly(...);
```

instead of

```
ON_CALL(foo, Bar(_))
    .WillByDefault(...);
```

This tells Google Mock that you do expect the calls and no warning should be
printed.

Also, you can control the verbosity using the `--gmock_verbose` flag.
If you find the output too noisy when debugging, just choose a less
verbose level.

## How can I delete the mock function's argument in an action? ##

If you find yourself needing to perform some action that's not
supported by Google Mock directly, remember that you can define your own
actions using
[MakeAction()](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Actions) or
[MakePolymorphicAction()](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Writing_New_Polymorphic_Actions),
or you can write a stub function and invoke it using
[Invoke()](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Using_Functions_Methods_Functors).

## MOCK\_METHODn()'s second argument looks funny.  Why don't you use the MOCK\_METHODn(Method, return\_type, arg\_1, ..., arg\_n) syntax? ##

What?!  I think it's beautiful. :-)

While which syntax looks more natural is a subjective matter to some
extent, Google Mock's syntax was chosen for several practical advantages it
has.

Try to mock a function that takes a map as an argument:
```
virtual int GetSize(const map<int, std::string>& m);
```

Using the proposed syntax, it would be:
```
MOCK_METHOD1(GetSize, int, const map<int, std::string>& m);
```

Guess what?  You'll get a compiler error as the compiler thinks that
`const map<int, std::string>& m` are **two**, not one, arguments. To work
around this you can use `typedef` to give the map type a name, but
that gets in the way of your work.  Google Mock's syntax avoids this
problem as the function's argument types are protected inside a pair
of parentheses:
```
// This compiles fine.
MOCK_METHOD1(GetSize, int(const map<int, std::string>& m));
```

You still need a `typedef` if the return type contains an unprotected
comma, but that's much rarer.

Other advantages include:
  1. `MOCK_METHOD1(Foo, int, bool)` can leave a reader wonder whether the method returns `int` or `bool`, while there won't be such confusion using Google Mock's syntax.
  1. The way Google Mock describes a function type is nothing new, although many people may not be familiar with it.  The same syntax was used in C, and the `function` library in `tr1` uses this syntax extensively.  Since `tr1` will become a part of the new version of STL, we feel very comfortable to be consistent with it.
  1. The function type syntax is also used in other parts of Google Mock's API (e.g. the action interface) in order to make the implementation tractable. A user needs to learn it anyway in order to utilize Google Mock's more advanced features.  We'd as well stick to the same syntax in `MOCK_METHOD*`!

## My code calls a static/global function.  Can I mock it? ##

You can, but you need to make some changes.

In general, if you find yourself needing to mock a static function,
it's a sign that your modules are too tightly coupled (and less
flexible, less reusable, less testable, etc).  You are probably better
off defining a small interface and call the function through that
interface, which then can be easily mocked.  It's a bit of work
initially, but usually pays for itself quickly.

This Google Testing Blog
[post](http://googletesting.blogspot.com/2008/06/defeat-static-cling.html)
says it excellently.  Check it out.

## My mock object needs to do complex stuff.  It's a lot of pain to specify the actions.  Google Mock sucks! ##

I know it's not a question, but you get an answer for free any way. :-)

With Google Mock, you can create mocks in C++ easily.  And people might be
tempted to use them everywhere. Sometimes they work great, and
sometimes you may find them, well, a pain to use. So, what's wrong in
the latter case?

When you write a test without using mocks, you exercise the code and
assert that it returns the correct value or that the system is in an
expected state.  This is sometimes called "state-based testing".

Mocks are great for what some call "interaction-based" testing:
instead of checking the system state at the very end, mock objects
verify that they are invoked the right way and report an error as soon
as it arises, giving you a handle on the precise context in which the
error was triggered.  This is often more effective and economical to
do than state-based testing.

If you are doing state-based testing and using a test double just to
simulate the real object, you are probably better off using a fake.
Using a mock in this case causes pain, as it's not a strong point for
mocks to perform complex actions.  If you experience this and think
that mocks suck, you are just not using the right tool for your
problem. Or, you might be trying to solve the wrong problem. :-)

## I got a warning "Uninteresting function call encountered - default action taken.."  Should I panic? ##

By all means, NO!  It's just an FYI.

What it means is that you have a mock function, you haven't set any
expectations on it (by Google Mock's rule this means that you are not
interested in calls to this function and therefore it can be called
any number of times), and it is called.  That's OK - you didn't say
it's not OK to call the function!

What if you actually meant to disallow this function to be called, but
forgot to write `EXPECT_CALL(foo, Bar()).Times(0)`?  While
one can argue that it's the user's fault, Google Mock tries to be nice and
prints you a note.

So, when you see the message and believe that there shouldn't be any
uninteresting calls, you should investigate what's going on.  To make
your life easier, Google Mock prints the function name and arguments
when an uninteresting call is encountered.

## I want to define a custom action.  Should I use Invoke() or implement the action interface? ##

Either way is fine - you want to choose the one that's more convenient
for your circumstance.

Usually, if your action is for a particular function type, defining it
using `Invoke()` should be easier; if your action can be used in
functions of different types (e.g. if you are defining
`Return(value)`), `MakePolymorphicAction()` is
easiest.  Sometimes you want precise control on what types of
functions the action can be used in, and implementing
`ActionInterface` is the way to go here. See the implementation of
`Return()` in `include/gmock/gmock-actions.h` for an example.

## I'm using the set-argument-pointee action, and the compiler complains about "conflicting return type specified".  What does it mean? ##

You got this error as Google Mock has no idea what value it should return
when the mock method is called.  `SetArgPointee()` says what the
side effect is, but doesn't say what the return value should be.  You
need `DoAll()` to chain a `SetArgPointee()` with a `Return()`.

See this [recipe](http://code.google.com/p/googlemock/wiki/V1_7_CookBook#Mocking_Side_Effects) for more details and an example.


## My question is not in your FAQ! ##

If you cannot find the answer to your question in this FAQ, there are
some other resources you can use:

  1. read other [wiki pages](http://code.google.com/p/googlemock/w/list),
  1. search the mailing list [archive](http://groups.google.com/group/googlemock/topics),
  1. ask it on [googlemock@googlegroups.com](mailto:googlemock@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googlemock) before you can post.).

Please note that creating an issue in the
[issue tracker](http://code.google.com/p/googlemock/issues/list) is _not_
a good way to get your answer, as it is monitored infrequently by a
very small number of people.

When asking a question, it's helpful to provide as much of the
following information as possible (people cannot help you if there's
not enough information in your question):

  * the version (or the revision number if you check out from SVN directly) of Google Mock you use (Google Mock is under active development, so it's possible that your problem has been solved in a later version),
  * your operating system,
  * the name and version of your compiler,
  * the complete command line flags you give to your compiler,
  * the complete compiler error messages (if the question is about compilation),
  * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter.