From adb158b7396cbdcda347fa298978408e531a03fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20Court=C3=A8s?= Date: Fri, 14 Dec 2018 11:10:25 +0100 Subject: deduplication: Gracefully handle ENOSPC raised by 'link' calls. Reported by Andreas Enge in . * guix/store/deduplication.scm (replace-with-link): Catch ENOSPC around 'get-temp-link'. Do nothing when 'get-temp-link' throws ENOSPC. Move code to restore PARENT's permissions outside of 'catch'. * tests/store-deduplication.scm ("deduplicate, ENOSPC"): New test. --- tests/store-deduplication.scm | 44 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/store-deduplication.scm b/tests/store-deduplication.scm index e438aa84c6..e2870a363d 100644 --- a/tests/store-deduplication.scm +++ b/tests/store-deduplication.scm @@ -48,7 +48,7 @@ (put-bytevector port data)))) identical) ;; Make the parent of IDENTICAL read-only. This should not prevent - ;; deduplication for inserting its hard link. + ;; deduplication from inserting its hard link. (chmod (dirname (second identical)) #o544) (call-with-output-file unique @@ -64,4 +64,46 @@ (stat:nlink (stat unique)) (map (compose stat:nlink stat) identical)))))) +(test-equal "deduplicate, ENOSPC" + (cons* #f ;inode comparison + (append (make-list 3 4) + (make-list 7 1))) ;'nlink' values + + ;; In this scenario the first 3 files are properly deduplicated and then we + ;; simulate a full '.links' directory where link(2) gets ENOSPC, thereby + ;; preventing deduplication of the subsequent files. + (call-with-temporary-directory + (lambda (store) + (let ((true-link link) + (links 0) + (data1 (string->utf8 "Hello, world!")) + (data2 (string->utf8 "Hi, world!")) + (identical (map (lambda (n) + (string-append store "/" (number->string n) + "/a/b/c")) + (iota 10))) + (populate (lambda (data) + (lambda (file) + (mkdir-p (dirname file)) + (call-with-output-file file + (lambda (port) + (put-bytevector port data))))))) + (for-each (populate data1) (take identical 5)) + (for-each (populate data2) (drop identical 5)) + (dynamic-wind + (lambda () + (set! link (lambda (old new) + (set! links (+ links 1)) + (if (<= links 3) + (true-link old new) + (throw 'system-error "link" "~A" '("Whaaat?!") + (list ENOSPC)))))) + (lambda () + (deduplicate store (nar-sha256 store) #:store store)) + (lambda () + (set! link true-link))) + + (cons (apply = (map (compose stat:ino stat) identical)) + (map (compose stat:nlink stat) identical)))))) + (test-end "store-deduplication") -- cgit v1.2.3