From: Hector Martin Date: Wed, 24 Feb 2016 14:58:32 +0000 (+0900) Subject: pybind/rados: track completions before calling aio functions X-Git-Tag: v10.1.0~273^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=6e901bac3024c15c7f7d0a0e0f4c84d52ed9eec6;p=ceph.git pybind/rados: track completions before calling aio functions Tracking completions is critical for memory safety - if the aio function succeeds, the completion must be tracked. However, if a KeyboardInterrupt or similar arrives between the call and the tracking, the completion will not be tracked. Fix this by tracking the completion before the aio call, and explicitly cleaning up in the failure case. This leaves the opposite problem, where an unexpected exception (other than simple error return from the aio function) will cause the completion to not be freed until the Ioctx is destroyed, but that is a relatively minor issue. Signed-off-by: Hector Martin --- diff --git a/src/pybind/rados/rados.pyx b/src/pybind/rados/rados.pyx index 54fe245aab6..c190286957b 100644 --- a/src/pybind/rados/rados.pyx +++ b/src/pybind/rados/rados.pyx @@ -1802,13 +1802,13 @@ cdef class Ioctx(object): uint64_t _offset = offset completion = self.__get_completion(oncomplete, onsafe) - + self.__track_completion(completion) with nogil: ret = rados_aio_write(self.io, _object_name, completion.rados_comp, _to_write, size, _offset) if ret < 0: + completion._cleanup() raise make_ex(ret, "error writing object %s" % object_name) - self.__track_completion(completion) return completion def aio_write_full(self, object_name, to_write, @@ -1844,13 +1844,14 @@ cdef class Ioctx(object): size_t size = len(to_write) completion = self.__get_completion(oncomplete, onsafe) + self.__track_completion(completion) with nogil: ret = rados_aio_write_full(self.io, _object_name, completion.rados_comp, _to_write, size) if ret < 0: + completion._cleanup() raise make_ex(ret, "error writing object %s" % object_name) - self.__track_completion(completion) return completion def aio_append(self, object_name, to_append, oncomplete=None, onsafe=None): @@ -1884,13 +1885,14 @@ cdef class Ioctx(object): size_t size = len(to_append) completion = self.__get_completion(oncomplete, onsafe) + self.__track_completion(completion) with nogil: ret = rados_aio_append(self.io, _object_name, completion.rados_comp, _to_append, size) if ret < 0: + completion._cleanup() raise make_ex(ret, "error appending object %s" % object_name) - self.__track_completion(completion) return completion def aio_flush(self): @@ -1946,12 +1948,13 @@ cdef class Ioctx(object): completion = self.__get_completion(oncomplete_, None) completion.buf = PyBytes_FromStringAndSize(NULL, length) ret_buf = PyBytes_AsString(completion.buf) + self.__track_completion(completion) with nogil: ret = rados_aio_read(self.io, _object_name, completion.rados_comp, ret_buf, _length, _offset) if ret < 0: + completion._cleanup() raise make_ex(ret, "error reading %s" % object_name) - self.__track_completion(completion) return completion def aio_remove(self, object_name, oncomplete=None, onsafe=None): @@ -1977,12 +1980,13 @@ cdef class Ioctx(object): char* _object_name = object_name completion = self.__get_completion(oncomplete, onsafe) + self.__track_completion(completion) with nogil: ret = rados_aio_remove(self.io, _object_name, completion.rados_comp) if ret < 0: + completion._cleanup() raise make_ex(ret, "error removing %s" % object_name) - self.__track_completion(completion) return completion def require_ioctx_open(self):