From 0eb27b96f267a1a8419efeb96d68e3773d70e049 Mon Sep 17 00:00:00 2001 From: Prashanth Pai Date: Thu, 5 Mar 2015 19:01:38 +0530 Subject: [PATCH] Handle ENOSPC in mkstemp() mkstemp() can fail with ENOSPC when filesystem runs out of inodes. And fallocate() used to raise DiskFileNoSpace for all OSErrors. Change-Id: I8c95cb710107d8e481d068b00eda53dd805c00a5 Signed-off-by: Prashanth Pai --- swift/obj/diskfile.py | 14 ++++++++--- test/unit/obj/test_diskfile.py | 44 ++++++++++++++++++++++++++++++++-- test/unit/obj/test_server.py | 2 +- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/swift/obj/diskfile.py b/swift/obj/diskfile.py index 28ca8af1e0..8d8a76887a 100644 --- a/swift/obj/diskfile.py +++ b/swift/obj/diskfile.py @@ -1603,14 +1603,22 @@ class DiskFile(object): """ if not exists(self._tmpdir): mkdirs(self._tmpdir) - fd, tmppath = mkstemp(dir=self._tmpdir) + try: + fd, tmppath = mkstemp(dir=self._tmpdir) + except OSError as err: + if err.errno in (errno.ENOSPC, errno.EDQUOT): + # No more inodes in filesystem + raise DiskFileNoSpace() + raise dfw = None try: if size is not None and size > 0: try: fallocate(fd, size) - except OSError: - raise DiskFileNoSpace() + except OSError as err: + if err.errno in (errno.ENOSPC, errno.EDQUOT): + raise DiskFileNoSpace() + raise dfw = DiskFileWriter(self._name, self._datadir, fd, tmppath, self._bytes_per_sync, self._threadpool) yield dfw diff --git a/test/unit/obj/test_diskfile.py b/test/unit/obj/test_diskfile.py index 22fd17aa1b..cc6747555c 100644 --- a/test/unit/obj/test_diskfile.py +++ b/test/unit/obj/test_diskfile.py @@ -1595,16 +1595,56 @@ class TestDiskFile(unittest.TestCase): def test_create_prealloc_oserror(self): df = self.df_mgr.get_diskfile(self.existing_device, '0', 'abc', '123', 'xyz') + for e in (errno.ENOSPC, errno.EDQUOT): + with mock.patch("swift.obj.diskfile.fallocate", + mock.MagicMock(side_effect=OSError( + e, os.strerror(e)))): + try: + with df.create(size=200): + pass + except DiskFileNoSpace: + pass + else: + self.fail("Expected exception DiskFileNoSpace") + + # Other OSErrors must not be raised as DiskFileNoSpace with mock.patch("swift.obj.diskfile.fallocate", mock.MagicMock(side_effect=OSError( errno.EACCES, os.strerror(errno.EACCES)))): try: with df.create(size=200): pass - except DiskFileNoSpace: + except OSError: pass else: - self.fail("Expected exception DiskFileNoSpace") + self.fail("Expected exception OSError") + + def test_create_mkstemp_no_space(self): + df = self.df_mgr.get_diskfile(self.existing_device, '0', 'abc', '123', + 'xyz') + for e in (errno.ENOSPC, errno.EDQUOT): + with mock.patch("swift.obj.diskfile.mkstemp", + mock.MagicMock(side_effect=OSError( + e, os.strerror(e)))): + try: + with df.create(size=200): + pass + except DiskFileNoSpace: + pass + else: + self.fail("Expected exception DiskFileNoSpace") + + # Other OSErrors must not be raised as DiskFileNoSpace + with mock.patch("swift.obj.diskfile.mkstemp", + mock.MagicMock(side_effect=OSError( + errno.EACCES, os.strerror(errno.EACCES)))): + try: + with df.create(size=200): + pass + except OSError: + pass + else: + self.fail("Expected exception OSError") def test_create_close_oserror(self): df = self.df_mgr.get_diskfile(self.existing_device, '0', 'abc', '123', diff --git a/test/unit/obj/test_server.py b/test/unit/obj/test_server.py index c8974deb42..1823a90140 100755 --- a/test/unit/obj/test_server.py +++ b/test/unit/obj/test_server.py @@ -4041,7 +4041,7 @@ class TestObjectController(unittest.TestCase): return '' def fake_fallocate(fd, size): - raise OSError(42, 'Unable to fallocate(%d)' % size) + raise OSError(errno.ENOSPC, os.strerror(errno.ENOSPC)) orig_fallocate = diskfile.fallocate try: