======================== Zadanie 2: bufor zapisów ======================== Data ogłoszenia: 31.03.2020 Termin oddania: 05.05.2020 (ostateczny 19.05.2020) Materiały dodatkowe =================== :download:`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``