Directory creation race condition in FileSystemStorage
|Reported by:||Piet Delport||Owned by:||nobody|
|Severity:||Normal||Keywords:||FileSystemStorage directory creation race condition|
|Cc:||Triage Stage:||Ready for checkin|
|Has patch:||yes||Needs documentation:||no|
|Needs tests:||no||Patch needs improvement:||no|
My company recently encountered the following problem on a production server:
Traceback (most recent call last): [...] File "[...]", line 191, in process_view storage.save(path, File([...])) File "[...]/python2.6/site-packages/django/core/files/storage.py", line 47, in save name = self._save(name, content) File "[...]/python2.6/site-packages/django/core/files/storage.py", line 146, in _save os.makedirs(directory) File "[...]/python2.6/os.py", line 157, in makedirs mkdir(name, mode) OSError: [Errno 17] File exists: '[MEDIA_ROOT]/avatars/foo'
I tracked this down to a race condition in
FileSystemStorage._save. When there is enough load, two concurrent processes can attempt to create the same intermediate directory, causing the second one to fail entirely.
To handle this robustly,
FileSystemStorage should catch the
os.makedirs and continue normally: I implemented this along with some tests, in the attached patch.
Note: For comparison, Python 3.2 added a keyword argument to
os.makedirs to do this: see Issue 9299: os.makedirs(): Add a keyword argument to suppress "File exists" exception.