Zadanie 2: bufor zapisów

Data ogłoszenia: 31.03.2020

Termin oddania: 05.05.2020 (ostateczny 19.05.2020)

Materiały dodatkowe

z2_test.tar.gz

Wprowadzenie

Syscall write jest starym i dobrze przyjętym narzędziem do modyfikacji plików. Ma jednak poważny problem: gdy program zacznie modyfikować plik i napotka błąd na którymś etapie, nie jest w stanie łatwo przywrócić pliku do stanu początkowego, powodując istnienie częściowo zmodyfikowanego pliku.

Zadanie

Napisać modyfikację do jądra pozwalającą na cofnięcie zmian wykonanych przez write (a właściwie na buforowanie ich i zaaplikowanie na właściwy plik dopiero, gdy poprosi o to użytkownik).

Dodać do flag syscalla open nową flagę O_BUFFERED_WRITE (o wartośći 040000000), która spowoduje buforowanie zapisów przed zaaplikowaniem ich na właściwy plik.

W przypadku zapisu do deskryptora pliku otwartego z taką flagą, zapis nie powinien być przesyłany do warstwy systemu plików — zamiast tego, zapisane dane powinny być magazynowane w buforze prywatnym dla danego deskryptora, by mogły być później zaaplikowane.

Za zapis uznajemy wykonanie syscalli modyfikujących plik: ftruncate, write, pwrite, writev, pwritev, pwritev2.

Odczyt na naszym deskryptorze pliku powinien pokazywać buforowane zmiany. Zmiany nie powinny być jednak widoczne (do momentu zatwierdzenia) przez jakiekolwiek inne otwarte deskryptory wskazujące na ten sam plik.

Zmodyfikować syscall fsync tak, aby wykonanie go na buforowanym deskryptorze pliku powodowało zatwierdzenie wszystkich buforowanych obecnie zmian (zaaplikowanie ich do pliku na dysku).

W przypadku zamknięcia deskryptora pliku z włączonym buforowaniem bez wywołania fsync, należy wyrzucić wszystkie buforowane zmiany.

Nie trzeba wspierać w zadaniu funkcji mmap — próba zamapowania pliku otwartego w ten sposób powinna się skończyć błędem. Nie trzeba też wspierać vmsplice, splice, tee, sendfile.

Nie trzeba wspierać kombinacji O_APPEND z O_BUFFERED_WRITE.

Założenia interakcji z innymi użytkownikami

W naszym deskryptorze powinniśmy pamiętać tylko faktycznie zmodyfikowane zakresy danych — zaaplikowanie zmian nie powinno zmienić żadnych danych w pliku poza obszarami zmienionymi przez write na naszym deskryptorze, nawet jeśli plik był równolegle zmieniany przez innych użytkowników. W szczególności, gdy dwóch różnych użytkowników otworzy ten sam plik w trybie buforowania i będzie równolegle wprowadzać zmiany w rozłącznych obszarach, po czym wywoła fsync, ostateczny stan pliku powinien uwzględniać zmiany obydwu użytkowników.

Może się zdarzyć, że zaaplikowanie zmian okaże się niemożliwe, gdy plik w międzyczasie zostanie skrócony (ftruncate) — w takim wypadku, fsync powinien zwrócić błąd.

Zasady oceniania

Za zadanie można uzyskać do 10 punktów. Na ocenę zadania składają się dwie części:

  • wynik testów (od 0 do 10 punktów)

  • ocena kodu rozwiązania (od 0 do -10 punktów)

Najczęstsze błędy - spis oznaczeń w USOSwebie

  1. Bezpośredni dostęp do pamięci userspace(np memcpy zamiast copy_*_user) (-0.5, max 3szt.)

  2. Brak sprawdzania wyniku alokacji pamiąci lub nieprawidłowa obsługa błędu (-0.5, max 3 szt.)

  3. Wyciek pamięci: brak kfree w obsłudze błędu (-0.2, max 3 szt.)

  4. Include pliku C zamiast dodanie go do systemu budowania (-0.2)

  5. Przekazywanie adresu z kernela do funkcji przyjmującej typ __user (-0.5, -0.0 przy jednoczesnym wystąpienu z #1)

  6. Wyciek: brak zwalniania struktur przy close (bez fsync) (-0.2)

  7. Zwracanie nieprawidłowo zakodowanych błedów (ENOMEM zamiast -ENOMEM) (-0.2)

  8. Zwracanie -EFAULT zamiast -ENOMEM przy braku pamięci (-0.2)

  9. Brak zwracania -EFAULT przy błędzie w copy_*_user (-0.5)

  10. Brak błędu przy wywołaniu mmap (-0.2)

  11. Błędy / deadlock przy wielu wątkach (-0.5)

  12. Brak poprawnej obsługi dużych (większych niż maksymalna alokacja kmalloc) zapisów / odczytów (-0.5)

Forma rozwiązania

Jako rozwiązanie należy wysłać paczkę zawierającą:

  • patcha na jądro w wersji 5.5.5, w jednym z następujących formatów:

    • patch wygenerowaniy przez diffa z opcjami -uprN nakładający się przez patch -p1

    • git format-patch

  • krótki opis rozwiązania

Rozwiązania prosimy nadsyłać na adres p.zuk@mimuw.edu.pl z kopią do mwk@mimuw.edu.pl.

Wskazówki

Aby proces przy odczytach poprawnie widział buforowane dane, należy przechwycić:

  • read, pread, readv, preadv, preadv2

  • sprawdzenie rozmiaru pliku przez fstat

  • lseek z opcją SEEK_END