내가 아는 한, 파일의 inode가 발견되면 데이터를 찾는 것은 간단합니다. inode에 저장된 디스크의 특정 위치에 액세스하면 됩니다.
그런데 문제는 시스템에 파일 경로가 주어지면 도대체 어떻게 인덱스 노드를 찾는 걸까요?
내 질문의 목적은 주로 B-트리가 실제 생활에서 어떻게 구현되는지 이해하는 것입니다. 나는 그것의 일반적인 아이디어를 이해하지만 그것이 Unix 파일 시스템에서 정확히 어떻게 구현되는지 (만약 있다면) 알고 싶습니다.
트리의 각 노드는 inode 번호를 저장하고, 리프도 inode 자체의 디스크 주소를 저장합니까? 아니면 파일 경로의 연속된 부분일까요?
디스크가 하드 드라이브인지 SSD인지에 따라 구현이 달라지나요?
답변1
IMHO: 두 가지 질문이 있습니다:
시스템에 파일 경로를 제공할 때 인덱스 노드를 정확하게 찾는 방법
그리고
B-트리가 실제 생활에서 어떻게 구현되는지 파악하고 싶습니다.
아마도 귀하의 질문은 inode가 어떻게 저장되는지(b-트리에) 또는 inode가 참조하는 데이터일 것입니다. 그렇다면 저는 대답할 수 없습니다.
첫 번째 문자 그대로의 질문에 대한 답변은 운영 체제에 따라 다르며 범위 not difficult
는 opaque
. 고전적인 시스템 호출(open, unlink)은 파일 이름 항목을 찾는 디렉토리를 읽고 (현대에서는 opendir()을 호출하여) 시작됩니다.
클래식 UNIX에서 파일 이름의 최대 길이는 14자입니다. 즉, inode용으로 2바이트(디렉토리 항목용으로 16바이트)가 남습니다. 파일 이름과 inode의 b-트리 구성은 없었습니다(그리고 여전히 그렇습니다). 검색은 디렉토리의 연속 읽기였습니다(그리고 지금도 그렇습니다). 이는 simple
반드시 확인해야 할 사항입니다.
더 긴 파일 이름을 허용하는 오늘날의 시스템에서도 디렉토리 항목의 기본 모양은 변경되지 않을 수 있습니다(2바이트(인덱스 노드), 14바이트(초기 파일 이름/전체 파일 이름)). (적어도 AIX에서는 모든 것, 심지어 디렉토리도 UNIX 관용어를 따릅니다. 모든 것이 파일이고 일부는 특별합니다.)
michael@x071:[/home/michael]ls -lia /tmp | head
total 287464
2 drwxrwxrwt 54 bin bin 36864 Jan 22 13:35 .
2 drwxr-xr-x 39 root system 4096 Jan 5 12:27 ..
5 drwxrwxrwt 2 root system 256 May 8 2013 .X11-unix
6 -rw-r----- 1 root system 0 May 23 2014 .ahafs.out.michael.10223652
7 -rw-r----- 1 root system 0 May 23 2014 .ahafs.out.michael.9502870
8 -r--r--r-- 1 root system 25 Jun 9 2013 .aix_ISMP_lock____.save
9 drwxrwxrwt 3 root system 4096 Dec 27 12:15 .com_ibm_tools_attach
62 -rw-r--r-- 1 root system 3124 Dec 27 11:21 .ctinst.log
63 -rw-r----- 1 michael felt 2578 Aug 16 2013 .htaccess
michael@x071:[/home/michael]od -dc /tmp | head -20
0000000 2 11776 0 0 0 0 0 0
\0 002 . \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
0000020 2 11822 0 0 0 0 0 0
\0 002 . . \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0
0000040 32848 11895 28530 27492 26994 11825 13109 13878
200 P . w o r k d i r . 1 3 5 6 6
0000060 5 11864 12593 11637 28265 30720 0 0
\0 005 . X 1 1 - u n i x \0 \0 \0 \0 \0
0000100 6 11873 26721 26227 11887 30068 11885 26979
\0 006 . a h a f s . o u t . m i c
0000120 7 11873 26721 26227 11887 30068 11885 26979
\0 \a . a h a f s . o u t . m i c
0000140 8 11873 27000 24393 21325 20575 27759 25451
\0 \b . a i x _ I S M P _ l o c k
0000160 9 11875 28525 24425 25197 24436 28527 27763
\0 \t . c o m _ i b m _ t o o l s
0000200 62 11875 29801 28275 29742 27759 26368 0
\0 > . c t i n s t . l o g \0 \0 \0
0000220 63 11880 29793 25443 25971 29440 0 0
\0 ? . h t a c c e s s \0 \0 \0 \0 \0
참고: 위의 내용은 Linux 시스템에서 시도되었습니다. 아마도 이제 B-트리로 구성되어 있을 것입니다. 모르겠어요. 다음과 같은 결과가 나오거든요.
michael@x067:~$ od -dc /tmp|head
od: /tmp: read error: Is a directory
0000000
따라서 전통적으로 (특수) 파일에 대한 inode "조회/매핑"은 디렉토리 항목의 처음 2바이트에 불과합니다. 인덱스 노드는 디스크에 위치하거나 B-트리와 같은 메모리에 저장됩니다.
AIX에서 'dirent' 구조는 다음 형식으로 "쉽게 찾을 수 있습니다".
#define _D_NAME_MAX 255
struct dirent {
__ulong64_t d_offset; /* real off after this entry */
ino_t d_ino; /* inode number of entry */
ushort_t d_reclen; /* length of this record */
ushort_t d_namlen; /* length of string in d_name */
char d_name[_D_NAME_MAX+1]; /* name must be no longer than this */
/* redefine w/#define when name decided */
};
Linux(3.2.XY 커널)의 경우 포함 파일에는 다음 구조가 포함되어 있습니다.
struct dirent
{
#ifndef __USE_FILE_OFFSET64
__ino_t d_ino;
__off_t d_off;
#else
__ino64_t d_ino;
__off64_t d_off;
#endif
unsigned short int d_reclen;
unsigned char d_type;
char d_name[256]; /* We must not include limits.h! */
};
둘 다(IMHO)는 기본적으로 동일합니다. 반환 시 readdir()을 호출하면 차이점을 제거할 수 있습니다.
Linux/GNU 방법:
/usr/include/dirent.h:
/* This is the data type of directory stream objects.
The actual structure is opaque to users. */
typedef struct __dirstream DIR;
참고: __dirstream에 대해 아무것도 찾을 수 없어서 이에 대한 "설명"을 추가했습니다.
opaque
extern DIR *opendir (__const char *__name) __nonnull ((1));
...
/* Read a directory entry from DIRP. Return a pointer to a `struct
dirent' describing the entry, or NULL for EOF or error. The
storage returned may be overwritten by a later readdir call on the
same DIR stream.
If the Large File Support API is selected we have to use the
appropriate interface.
This function is a possible cancellation point and therefore not
marked with __THROW. */
#ifndef __USE_FILE_OFFSET64
extern struct dirent *readdir (DIR *__dirp) __nonnull ((1));
#else
# ifdef __REDIRECT
extern struct dirent *__REDIRECT (readdir, (DIR *__dirp), readdir64)
__nonnull ((1));
# else
# define readdir readdir64
# endif
#endif
#ifdef __USE_LARGEFILE64
extern struct dirent64 *readdir64 (DIR *__dirp) __nonnull ((1));
#endif
AIX의 경우:
/*
* Definitions for library routines operating on directories.
*/
typedef struct _dirdesc {
#ifdef _ALL_SOURCE
int dd_fd; /* file descriptor of directory */
blksize_t dd_blksize; /* this filesystem's block size */
char *dd_buf; /* malloc'd buffer depending of fs bsize */
long dd_size; /* size of buffer */
long dd_flag; /* private flags for readdir, unused */
off_t dd_loc; /* logical(dirent) offset in directory */
off_t dd_curoff; /* real offset in directory corresponding
* to dd_loc */
#else
int __dd_fd; /* file descriptor of directory */
blksize_t __dd_blksize; /* this filesystem's block size */
char *__dd_buf; /* malloc'd buffer depending of fs bsize */
long __dd_size; /* size of buffer */
long __dd_flag; /* private flags for readdir, unused */
off_t __dd_loc; /* logical(dirent) offset in directory */
off_t __dd_curoff; /* real offset in directory corresponding
* to dd_loc */
#endif
#if defined(_THREAD_SAFE) && defined(_ALL_SOURCE)
void *dd_lock; /* for inter-thread locking */
#endif
} DIR;
...
extern DIR *opendir(const char *);
extern struct dirent *readdir(DIR *);
즉, IMHO는 OS에 따라 구조가 on disk
매우 간단하거나 opaque
. 커널에서는 opaque
애플리케이션 코드를 변경하지 않고도 조직을 수정할 수 있는 조직이라면 놀라지 않을 것입니다.