Notice
Recent Posts
Recent Comments
Link
«   2025/10   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

JunHyeok

[PintOS - Userprog] Create & Remove 본문

PintOS

[PintOS - Userprog] Create & Remove

junhyeok-log 2024. 5. 28. 13:39

create 시스템 콜

create

bool create (const char *file, unsigned initial_size) {
    is_valid_addr(file);
    return filesys_create(file, initial_size);
}

create 시스템 콜 함수는 주어진 파일 이름(file)과 초기 크기(initial_size)를 사용하여 파일을 생성하는 시스템 콜입니다. 입력된 주소가 유효한지 확인한 후, filesys_create 함수를 호출하여 실제 파일을 생성합니다.

🤔 이 함수도 open, read와 같이 구현 자체는 정말 간단하다! 😼

2. filesys_create

/* Creates a file named NAME with the given INITIAL_SIZE.
 * Returns true if successful, false otherwise.
 * Fails if a file named NAME already exists,
 * or if internal memory allocation fails. */

bool filesys_create (const char *name, off_t initial_size) {
    disk_sector_t inode_sector = 0;
    struct dir *dir = dir_open_root ();
    bool success = (dir != NULL
            && free_map_allocate (1, &inode_sector)
            && inode_create (inode_sector, initial_size)
            && dir_add (dir, name, inode_sector));
    if (!success && inode_sector != 0)
        free_map_release (inode_sector, 1);
    dir_close (dir);

    return success;
}

filesys_create 함수는 파일 시스템에서 주어진 이름(name)과 초기 크기(initial_size)를 가진 파일을 생성합니다. 주요 과정은 다음과 같습니다:

  1. 루트 디렉토리를 엽니다.
  2. free map 에서 새로운 섹터를 할당합니다.
  3. 새 inode를 생성합니다.
  4. 디렉토리에 파일 이름을 추가합니다.

3. free_map_allocate

bool free_map_allocate (size_t cnt, disk_sector_t *sectorp) {
    disk_sector_t sector = bitmap_scan_and_flip (free_map, 0, cnt, false);
    if (sector != BITMAP_ERROR
            && free_map_file != NULL
            && !bitmap_write (free_map, free_map_file)) {
        bitmap_set_multiple (free_map, sector, cnt, false);
        sector = BITMAP_ERROR;
    }
    if (sector != BITMAP_ERROR)
        *sectorp = sector;
    return sector != BITMAP_ERROR;
}

free_map_allocate 함수는 free map 에서 연속적인 섹터를 할당하고, 첫 번째 섹터를 sectorp에 저장합니다.

✅ 성공 시 true
❌ 실패 시 false를 반환합니다.

4. inode_create

bool inode_create (disk_sector_t sector, off_t length) {
    struct inode_disk *disk_inode = NULL;
    bool success = false;

    ASSERT (length >= 0);
    disk_inode = calloc (1, sizeof *disk_inode);
    if (disk_inode != NULL) {
        size_t sectors = bytes_to_sectors (length);
        disk_inode->length = length;
        disk_inode->magic = INODE_MAGIC;
        if (free_map_allocate (sectors, &disk_inode->start)) {
            disk_write (filesys_disk, sector, disk_inode);
    // Inode 생성 로직 ........
        free(disk_inode)
}

inode_create 설명

  1. 메모리 할당

   disk_inode = calloc (1, sizeof *disk_inode);

disk_inodecalloc 함수를 통해 메모리를 할당받습니다. calloc은 메모리를 0으로 초기화하며, sizeof *disk_inode 크기만큼 할당합니다.

  1. 초기화
   if (disk_inode != NULL) {
       size_t sectors = bytes_to_sectors(length);
       disk_inode->length = length;
       disk_inode->magic = INODE_MAGIC;

할당받은 메모리가 NULL이 아닌지 확인한 후, 파일의 길이에 맞게 필요한 섹터 수를 계산합니다. 그리고 disk_inode의 길이와 매직 넘버를 설정합니다.

  1. 섹터 할당 및 기록
   if (free_map_allocate (sectors, &disk_inode->start)) {
       disk_write (filesys_disk, sector, disk_inode);

free_map_allocate 함수를 호출하여 필요한 섹터를 할당받고, 성공하면 disk_write 함수를 사용해 디스크에 disk_inode를 기록합니다.

메모리 해제

마지막에 free (disk_inode)를 해주는 이유는 동적 메모리 할당 후, 사용이 끝난 메모리를 해제하여 메모리 누수를 방지하기 위함입니다.
왜냐하면 우리는 disk_write (filesys_disk, sector, disk_inode) 을 사용하여, disk에 기록했기 때문이죠! 🥳

  • disk_inode를 동적으로 할당하고 초기화합니다.
  • 필요한 섹터를 할당받고, 할당이 성공하면 disk_write 합니다.
  • disk_inode의 사용이 끝난 후, 할당된 메모리를 free를 사용해 해제합니다.

5. dir_add

bool dir_add (struct dir *dir, const char *name, disk_sector_t inode_sector) {
    struct dir_entry e;
    off_t ofs;
    bool success = false;

    ASSERT (dir != NULL);
    ASSERT (name != NULL);

    /* Check NAME for validity. */
    if (*name == '\0' || strlen (name) > NAME_MAX)
        return false;

    /* Check that NAME is not in use. */
    if (lookup (dir, name, NULL, NULL))
        goto done;

    /* Set OFS to offset of free slot. */
    for (ofs = 0; inode_read_at (dir->inode, &e, sizeof e, ofs) == sizeof e;
            ofs += sizeof e)
        if (!e.in_use)
            break;

    /* Write slot. */
    e.in_use = true;
    strlcpy (e.name, name, sizeof e.name);
    e.inode_sector = inode_sector;
    success = inode_write_at (dir->inode, &e, sizeof e, ofs) == sizeof e;

done:
    return success;
}

dir_add 함수는 디렉토리에 파일 이름을 추가합니다.

  1. 이름의 유효성을 검사하고 (*name == '\0' || strlen (name) > NAME_MAX),
  2. 디렉토리에 이미 같은 이름의 파일이 있는지 확인한 후 lookup (dir, name, NULL, NULL)
  3. 새로운 디렉토리 엔트리를 작성합니다.

Remove 시스템 콜

remove

bool remove(const char *file) {
    is_valid_addr(file);
    return filesys_remove(file);
}

filesys_remove 함수

/* Deletes the file named NAME.
 * Returns true if successful, false on failure.
 * Fails if no file named NAME exists,
 * or if an internal memory allocation fails. */
bool
filesys_remove (const char *name) {
    struct dir *dir = dir_open_root ();
    bool success = dir != NULL && dir_remove (dir, name);
    dir_close (dir);

    return success;
}

filesys_remove 함수 설명

  1. remove 시스템 콜

    • 주소 유효성 검사

      is_valid_addr(file);

      file 포인터가 유효한 주소인지 확인합니다. 유효하지 않은 경우 시스템 콜이 실패할 수 있습니다.

    • 파일 삭제 시도

      return filesys_remove(file);

      filesys_remove 함수를 호출하여 파일을 삭제합니다. 이 함수는 파일 삭제의 성공 여부를 반환합니다.

  2. filesys_remove 함수

    • 루트 디렉토리 열기

      struct dir *dir = dir_open_root ();

      파일 시스템의 루트 디렉토리를 엽니다. dir_open_root 함수는 루트 디렉토리의 inode를 열고, 이를 사용하여 디렉토리 구조체를 반환합니다.

    • 파일 제거 시도

      bool success = dir != NULL && dir_remove (dir, name);
      1. 루트 디렉토리가 성공적으로 열렸는지 확인합니다 (dir != NULL).
      2. dir_remove 함수를 호출하여 주어진 이름의 파일을 삭제합니다. 이 함수는 성공하면 true를, 실패하면 false를 반환합니다.
    • 디렉토리 닫기

      dir_close (dir);

      dir_close 함수를 호출하여 디렉토리를 닫고, 메모리를 해제합니다.

    • 결과 반환

      return success;

      파일 삭제 작업의 성공 여부를 반환합니다.

요약

  • remove 시스템 콜

    1. file 주소가 유효한지 확인합니다.
    2. filesys_remove 함수를 호출하여 파일을 삭제합니다.
    3. 파일 삭제의 성공 여부를 반환합니다.
  • filesys_remove 함수

    1. 루트 디렉토리를 엽니다.
    2. 루트 디렉토리가 성공적으로 열리고, 파일이 성공적으로 삭제되었는지 확인합니다.
    3. 디렉토리를 닫고, 메모리를 해제합니다.
    4. 파일 삭제의 성공 여부를 반환합니다.

Pintos와 Linux의 system call 비교. 🐣 🆚 🐧

공통점

  1. 파일 이름과 초기 크기: 두 시스템 모두 파일을 생성할 때 파일 이름과 초기 크기를 인자로 받습니다.
  2. 파일 시스템 내 데이터 구조: 파일을 생성할 때 내부적으로 inode와 같은 데이터 구조를 사용하여 파일 메타데이터를 관리합니다.

차이점

  1. 구현 세부사항:
    • Pintos: 교육 목적으로 설계된 간단한 운영체제로, 파일 시스템이 메모리 내에 간단하게 구현되어 있습니다. 파일 생성 과정에서 free_map_allocate, inode_create, dir_add와 같은 함수들을 통해 파일 시스템의 내부 구조를 다룹니다.
    • Linux: 복잡하고 성능 최적화된 파일 시스템을 가지고 있습니다. Linux의 create 시스템 콜은 VFS(Virtual File System) 레이어를 통해 다양한 파일 시스템(ext4, xfs 등)을 지원하며, 각 파일 시스템별로 최적화된 파일 생성 방식을 사용합니다.
  2. 동시성 처리:
    • Pintos: 간단한 락 메커니즘을 사용하여 동시성 문제를 처리합니다.
    • Linux: 복잡한 락킹 메커니즘과 다양한 동시성 제어 기법(RCU, 스핀락 등)을 사용하여 높은 성능과 안정성을 보장합니다.
  3. 에러 리턴 방식:
    • Pintos: 주로 bool 타입을 사용하여 성공 여부를 반환합니다.
    • Linux: 다양한 에러 코드를 반환하여 세밀한 오류 정보를 제공합니다 (예: -ENOMEM, -EEXIST 등).
  4. 파일 시스템 확장성:
    • Pintos: 교육 목적이므로 확장성이 제한적입니다.
    • Linux: 다양한 파일 시스템을 지원하며(Virtual File System), 대규모 파일 시스템에서도 효율적으로 작동하도록 설계되어 있습니다.

결론

PintOS로 파일 시스템을 다뤄봤다고 하지만, 아직 부족한게 많다고 느꼇다. 실제로 File system이 어떻게 관리되는지 궁금해졌으며 시간이 날 때마다 추가적으로 정리를 해야겠다! 😼😼

'PintOS' 카테고리의 다른 글

[PintOS - Userprog] Fork, Exec, Wait 에 들어가기 앞서...  (0) 2024.05.29
[PintOS - Userprog] Write  (0) 2024.05.28
[PintOS - Userprog] Seek & Tell  (0) 2024.05.28
[PintOS - Userprog] Read  (0) 2024.05.28
[PintOS - Userprog] Open & Close  (0) 2024.05.27