int pt_section_map_share(struct pt_section *section) { uint16_t mcount; int errcode; if (!section) return -pte_internal; errcode = pt_section_lock(section); if (errcode < 0) return errcode; mcount = section->mcount; if (!mcount) { (void) pt_section_unlock(section); return -pte_internal; } mcount += 1; if (!mcount) { (void) pt_section_unlock(section); return -pte_overflow; } section->mcount = mcount; return pt_section_unlock(section); }
int pt_section_put(struct pt_section *section) { uint16_t ucount, mcount; int errcode; if (!section) return -pte_internal; errcode = pt_section_lock(section); if (errcode < 0) return errcode; mcount = section->mcount; ucount = section->ucount; if (ucount > 1) { section->ucount = ucount - 1; return pt_section_unlock(section); } errcode = pt_section_unlock(section); if (errcode < 0) return errcode; if (!ucount || mcount) return -pte_internal; pt_section_free(section); return 0; }
static int pt_sec_posix_map_success(struct pt_section *section) { uint16_t mcount; int errcode, status; if (!section) return -pte_internal; mcount = section->mcount + 1; if (!mcount) { (void) pt_section_unlock(section); return -pte_overflow; } section->mcount = mcount; errcode = pt_section_unlock(section); if (errcode < 0) return errcode; status = pt_section_on_map(section); if (status < 0) { /* We had to release the section lock for pt_section_on_map() so * @section may have meanwhile been mapped by other threads. * * We still want to return the error so we release our mapping. * Our caller does not yet know whether pt_section_map() * succeeded. */ (void) pt_section_unmap(section); return status; } return 0; }
int pt_section_unmap(struct pt_section *section) { uint16_t mcount; int errcode, status; if (!section) return -pte_internal; errcode = pt_section_lock(section); if (errcode < 0) return errcode; mcount = section->mcount; errcode = -pte_nomap; if (!mcount) goto out_unlock; section->mcount = mcount -= 1; if (mcount) return pt_section_unlock(section); errcode = -pte_internal; if (!section->unmap) goto out_unlock; status = section->unmap(section); pt_bcache_free(section->bcache); section->bcache = NULL; errcode = pt_section_unlock(section); if (errcode < 0) return errcode; return status; out_unlock: (void) pt_section_unlock(section); return errcode; }
int pt_section_get(struct pt_section *section) { uint16_t ucount; int errcode; if (!section) return -pte_internal; errcode = pt_section_lock(section); if (errcode < 0) return errcode; ucount = section->ucount + 1; if (!ucount) { (void) pt_section_unlock(section); return -pte_internal; } section->ucount = ucount; return pt_section_unlock(section); }
int pt_section_memsize(struct pt_section *section, uint64_t *size) { int errcode, status; errcode = pt_section_lock(section); if (errcode < 0) return errcode; status = pt_section_memsize_locked(section, size); errcode = pt_section_unlock(section); if (errcode < 0) return errcode; return status; }
int pt_section_map(struct pt_section *section) { const char *filename; uint16_t mcount; FILE *file; int fd, errcode; if (!section) return -pte_internal; errcode = pt_section_lock(section); if (errcode < 0) return errcode; mcount = section->mcount + 1; if (mcount > 1) { section->mcount = mcount; return pt_section_unlock(section); } errcode = -pte_internal; if (!mcount) goto out_unlock; if (section->mapping) goto out_unlock; filename = section->filename; if (!filename) goto out_unlock; errcode = -pte_bad_image; fd = open(filename, O_RDONLY); if (fd == -1) goto out_unlock; errcode = check_file_status(section, fd); if (errcode < 0) goto out_fd; /* We close the file on success. This does not unmap the section. */ errcode = pt_sec_posix_map(section, fd); if (!errcode) { section->mcount = 1; close(fd); return pt_section_unlock(section); } /* Fall back to file based sections - report the original error * if we fail to convert the file descriptor. */ file = fdopen(fd, "rb"); if (!file) goto out_fd; /* We need to keep the file open on success. It will be closed when * the section is unmapped. */ errcode = pt_sec_file_map(section, file); if (!errcode) { section->mcount = 1; return pt_section_unlock(section); } fclose(file); goto out_unlock; out_fd: close(fd); out_unlock: (void) pt_section_unlock(section); return errcode; }
int pt_section_alloc_bcache(struct pt_section *section) { struct pt_image_section_cache *iscache; struct pt_block_cache *bcache; uint64_t ssize, memsize; uint32_t csize; int errcode; if (!section) return -pte_internal; if (!section->mcount) return -pte_internal; ssize = pt_section_size(section); csize = (uint32_t) ssize; if (csize != ssize) return -pte_not_supported; memsize = 0ull; /* We need to take both the attach and the section lock in order to pair * the block cache allocation and the resize notification. * * This allows map notifications in between but they only change the * order of sections in the cache. * * The attach lock needs to be taken first. */ errcode = pt_section_lock_attach(section); if (errcode < 0) return errcode; errcode = pt_section_lock(section); if (errcode < 0) goto out_alock; bcache = pt_section_bcache(section); if (bcache) { errcode = 0; goto out_lock; } bcache = pt_bcache_alloc(csize); if (!bcache) { errcode = -pte_nomem; goto out_lock; } /* Install the block cache. It will become visible and may be used * immediately. * * If we fail later on, we leave the block cache and report the error to * the allocating decoder thread. */ section->bcache = bcache; errcode = pt_section_memsize_locked(section, &memsize); if (errcode < 0) goto out_lock; errcode = pt_section_unlock(section); if (errcode < 0) goto out_alock; if (memsize) { iscache = section->iscache; if (iscache) { errcode = pt_iscache_notify_resize(iscache, section, memsize); if (errcode < 0) goto out_alock; } } return pt_section_unlock_attach(section); out_lock: (void) pt_section_unlock(section); out_alock: (void) pt_section_unlock_attach(section); return errcode; }