register_filesystem을 통해서 전달되는 구조체의 내용 중 가장 중요한 부분은 바로 super block에 대한 정보를 반환하는 get_sb 함수이다. 이 함수를 통해서 파일시스템의 가장 중요하며 시작점에 해당하는 역할을 하는 슈퍼블럭에 대한 구조체인 struct super_block을 얻을 수 있다.
슈퍼블럭은 파일시스템마다 불리는 이름이 다르며, MS-DOS의 경우에는 FAT(File Allocation Table)이라고 부른다. 여기에는 파일을 찾기 위한 기본적인 정보들이 들어 있다. 물론, 유닉스 계열의 파일 시스템에서는 이에 대한 내용이 i-node 테이블에서 주로 관리된다. 일반적으로 슈퍼블럭은 해당 파일시스템에 대한 기본적인 정보들을 가지고 있다고 보면 된다.
다음 그림은 ext2 파일 시스템의 전체 레이아웃으로서 슈퍼블럭이 차지하는 위치를 알 수 있다.
파일 시스템을 등록할 때 전달되는 struct file_system_type의 get_sb() 함수를 통해 반환되도록 되어 있는 struct super_block 구조체는 슈퍼 블럭에서 관리하는 정보들을 모두 얻을 수 있도록 되어 있다. 물론, 파일 시스템에 다라서는 일부 내용이 무의미할 수 도 있다. 어쨌든, 파티션상에 존재하는 해당 파일 시스템에 대해서 데이타를 다룰 때 사용하게 되는 여러가지 정보들이 여기에 존재하게 된다.
이 중에서 슈퍼블럭을 다루기 위해서 필요한 연산들이 916번째 줄에 있는 struct super_operations *s_op 필드이다. struct super_operations는 다음과 같이 정의되어 있다.
super_operation 구조체에서 하는 일은 super_block을 다루는 코드와 함께 super_block을 기반으로 실제 파일에 해당하는 정보를 찾을 수 있는 inode를 다루는 연산들로 구성되어 있다. 새로운 파일이 생성될 경우에는 alloc_inode를 사용하게 되며, 파일 정보와 관련해서 read_inode(), write_inode() 함수들도 사용하게 된다. mount 관련된 구조체인 vfsmount는 이 전번 글에서 간단히 살펴보았으므로 여기에서는 그냥 넘어간다.
inode는 실제로 파일을 만들기 위한 기본이 되는 정보로서 이를 통해 어떤 파일이 어디에 있으며, 어떠한 속성으로 만들어 졌는지, 크기는 얼마인지, 소유자는 누구인지, 접근 권한은 어떻게 되는지 등의 정보를 볼 수 있다. 즉, 일반적으로 ls -l 명령을 사용했을 때 나오는 결과에 해당하는 정보를 가지고 있다고 보면 된다.
i-node를 통해 파일의 실제 데이타를 제외한 모든 정보를 얻을 수 있다. 일부 파일시스템(FAT, FAT16, FAT32 등등)에 대해서는 struct inode 구조체의 일부 필드가 의미없을 수 도 있다. inode 구조체에서는 실제 inode를 다루는 방법과 파일을 다루는 방법을 위해서 두 가지 구조체를 제공하고 있다.
먼저, inode를 다루는 함수들을 위해서는 struct inode_operations *i_op 필드가 제공된다. 이 구조체는 다음과 같은 형태를 가지고 있다.
inode_operations에서는 실제 파일 정보를 만들고 제거하는 다양한 방법을 제공한다.
파일 내용을 다루는 연산을 위해서는 struct file_operations *i_fop 필드가 제공된다. 이 구조체는 다음과 같은 형태를 가지고 있다.
파일 시스템을 만드는 것은 결국 이러한 연산자들을 잘 구성하는 것으로 시작한다고 볼 수 있다. 물론, 각각은 실제 물리적인 장치에 어떻게 배치되느냐도 중요하지만, 일단은 이러한 함수들에 내용을 넣는 것부터 시작해 보는 것도 괜찮을 것이다.
아래 코드는 이러한 내용들을 간단히 채워 넣은 파일 시스템 예제 코드로서 아래 주소에서 코드 및 설명을 볼 수 있다.
<참조 위치 : http://www.geocities.com/ravikiran_uvs/articles/rkfs.html>
/* readpage */
/*
* Data declarations
*/
return 0;
}
static int
rkfs_init_module(void) {
int err;
다음번부터는 실제 파일 시스템들을 하나씩 들쳐볼까 한다. 여러모로 어려운 부분이 있겠지만, 실제 파일 시스템을 살펴보는 것이 제일 좋은 방법이라 생각된다.
슈퍼블럭은 파일시스템마다 불리는 이름이 다르며, MS-DOS의 경우에는 FAT(File Allocation Table)이라고 부른다. 여기에는 파일을 찾기 위한 기본적인 정보들이 들어 있다. 물론, 유닉스 계열의 파일 시스템에서는 이에 대한 내용이 i-node 테이블에서 주로 관리된다. 일반적으로 슈퍼블럭은 해당 파일시스템에 대한 기본적인 정보들을 가지고 있다고 보면 된다.
다음 그림은 ext2 파일 시스템의 전체 레이아웃으로서 슈퍼블럭이 차지하는 위치를 알 수 있다.
908 struct super_block {
909 struct list_head s_list; /* Keep this first */
910 dev_t s_dev; /* search index; _not_ kdev_t */
911 unsigned long s_blocksize;
912 unsigned char s_blocksize_bits;
913 unsigned char s_dirt;
914 unsigned long long s_maxbytes; /* Max file size */
915 struct file_system_type *s_type;
916 const struct super_operations *s_op;
917 struct dquot_operations *dq_op;
918 struct quotactl_ops *s_qcop;
919 struct export_operations *s_export_op;
920 unsigned long s_flags;
921 unsigned long s_magic;
922 struct dentry *s_root;
923 struct rw_semaphore s_umount;
924 struct mutex s_lock;
925 int s_count;
926 int s_syncing;
927 int s_need_sync_fs;
928 atomic_t s_active;
929 #ifdef CONFIG_SECURITY
930 void *s_security;
931 #endif
932 struct xattr_handler **s_xattr;
933
934 struct list_head s_inodes; /* all inodes */
935 struct list_head s_dirty; /* dirty inodes */
936 struct list_head s_io; /* parked for writeback */
937 struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting */
938 struct list_head s_files;
939
940 struct block_device *s_bdev;
941 struct mtd_info *s_mtd;
942 struct list_head s_instances;
943 struct quota_info s_dquot; /* Diskquota specific options */
944
945 int s_frozen;
946 wait_queue_head_t s_wait_unfrozen;
947
948 char s_id[32]; /* Informational name */
949
950 void *s_fs_info; /* Filesystem private info */
951
952 /*
953 * The next field is for VFS *only*. No filesystems have any business
954 * even looking at it. You had been warned.
955 */
956 struct mutex s_vfs_rename_mutex; /* Kludge */
957
958 /* Granularity of c/m/atime in ns.
959 Cannot be worse than a second */
960 u32 s_time_gran;
961
962 /*
963 * Filesystem subtype. If non-empty the filesystem type field
964 * in /proc/mounts will be "type.subtype"
965 */
966 char *s_subtype;
967 };
909 struct list_head s_list; /* Keep this first */
910 dev_t s_dev; /* search index; _not_ kdev_t */
911 unsigned long s_blocksize;
912 unsigned char s_blocksize_bits;
913 unsigned char s_dirt;
914 unsigned long long s_maxbytes; /* Max file size */
915 struct file_system_type *s_type;
916 const struct super_operations *s_op;
917 struct dquot_operations *dq_op;
918 struct quotactl_ops *s_qcop;
919 struct export_operations *s_export_op;
920 unsigned long s_flags;
921 unsigned long s_magic;
922 struct dentry *s_root;
923 struct rw_semaphore s_umount;
924 struct mutex s_lock;
925 int s_count;
926 int s_syncing;
927 int s_need_sync_fs;
928 atomic_t s_active;
929 #ifdef CONFIG_SECURITY
930 void *s_security;
931 #endif
932 struct xattr_handler **s_xattr;
933
934 struct list_head s_inodes; /* all inodes */
935 struct list_head s_dirty; /* dirty inodes */
936 struct list_head s_io; /* parked for writeback */
937 struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting */
938 struct list_head s_files;
939
940 struct block_device *s_bdev;
941 struct mtd_info *s_mtd;
942 struct list_head s_instances;
943 struct quota_info s_dquot; /* Diskquota specific options */
944
945 int s_frozen;
946 wait_queue_head_t s_wait_unfrozen;
947
948 char s_id[32]; /* Informational name */
949
950 void *s_fs_info; /* Filesystem private info */
951
952 /*
953 * The next field is for VFS *only*. No filesystems have any business
954 * even looking at it. You had been warned.
955 */
956 struct mutex s_vfs_rename_mutex; /* Kludge */
957
958 /* Granularity of c/m/atime in ns.
959 Cannot be worse than a second */
960 u32 s_time_gran;
961
962 /*
963 * Filesystem subtype. If non-empty the filesystem type field
964 * in /proc/mounts will be "type.subtype"
965 */
966 char *s_subtype;
967 };
파일 시스템을 등록할 때 전달되는 struct file_system_type의 get_sb() 함수를 통해 반환되도록 되어 있는 struct super_block 구조체는 슈퍼 블럭에서 관리하는 정보들을 모두 얻을 수 있도록 되어 있다. 물론, 파일 시스템에 다라서는 일부 내용이 무의미할 수 도 있다. 어쨌든, 파티션상에 존재하는 해당 파일 시스템에 대해서 데이타를 다룰 때 사용하게 되는 여러가지 정보들이 여기에 존재하게 된다.
이 중에서 슈퍼블럭을 다루기 위해서 필요한 연산들이 916번째 줄에 있는 struct super_operations *s_op 필드이다. struct super_operations는 다음과 같이 정의되어 있다.
1161 struct super_operations {
1162 struct inode *(*alloc_inode)(struct super_block *sb);
1163 void (*destroy_inode)(struct inode *);
1164
1165 void (*read_inode) (struct inode *);
1166
1167 void (*dirty_inode) (struct inode *);
1168 int (*write_inode) (struct inode *, int);
1169 void (*put_inode) (struct inode *);
1170 void (*drop_inode) (struct inode *);
1171 void (*delete_inode) (struct inode *);
1172 void (*put_super) (struct super_block *);
1173 void (*write_super) (struct super_block *);
1174 int (*sync_fs)(struct super_block *sb, int wait);
1175 void (*write_super_lockfs) (struct super_block *);
1176 void (*unlockfs) (struct super_block *);
1177 int (*statfs) (struct dentry *, struct kstatfs *);
1178 int (*remount_fs) (struct super_block *, int *, char *);
1179 void (*clear_inode) (struct inode *);
1180 void (*umount_begin) (struct vfsmount *, int);
1181
1182 int (*show_options)(struct seq_file *, struct vfsmount *);
1183 int (*show_stats)(struct seq_file *, struct vfsmount *);
1184 #ifdef CONFIG_QUOTA
1185 ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
1186 ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
1187 #endif
1188 };
1162 struct inode *(*alloc_inode)(struct super_block *sb);
1163 void (*destroy_inode)(struct inode *);
1164
1165 void (*read_inode) (struct inode *);
1166
1167 void (*dirty_inode) (struct inode *);
1168 int (*write_inode) (struct inode *, int);
1169 void (*put_inode) (struct inode *);
1170 void (*drop_inode) (struct inode *);
1171 void (*delete_inode) (struct inode *);
1172 void (*put_super) (struct super_block *);
1173 void (*write_super) (struct super_block *);
1174 int (*sync_fs)(struct super_block *sb, int wait);
1175 void (*write_super_lockfs) (struct super_block *);
1176 void (*unlockfs) (struct super_block *);
1177 int (*statfs) (struct dentry *, struct kstatfs *);
1178 int (*remount_fs) (struct super_block *, int *, char *);
1179 void (*clear_inode) (struct inode *);
1180 void (*umount_begin) (struct vfsmount *, int);
1181
1182 int (*show_options)(struct seq_file *, struct vfsmount *);
1183 int (*show_stats)(struct seq_file *, struct vfsmount *);
1184 #ifdef CONFIG_QUOTA
1185 ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
1186 ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
1187 #endif
1188 };
super_operation 구조체에서 하는 일은 super_block을 다루는 코드와 함께 super_block을 기반으로 실제 파일에 해당하는 정보를 찾을 수 있는 inode를 다루는 연산들로 구성되어 있다. 새로운 파일이 생성될 경우에는 alloc_inode를 사용하게 되며, 파일 정보와 관련해서 read_inode(), write_inode() 함수들도 사용하게 된다. mount 관련된 구조체인 vfsmount는 이 전번 글에서 간단히 살펴보았으므로 여기에서는 그냥 넘어간다.
inode는 실제로 파일을 만들기 위한 기본이 되는 정보로서 이를 통해 어떤 파일이 어디에 있으며, 어떠한 속성으로 만들어 졌는지, 크기는 얼마인지, 소유자는 누구인지, 접근 권한은 어떻게 되는지 등의 정보를 볼 수 있다. 즉, 일반적으로 ls -l 명령을 사용했을 때 나오는 결과에 해당하는 정보를 가지고 있다고 보면 된다.
530 struct inode {
531 struct hlist_node i_hash;
532 struct list_head i_list;
533 struct list_head i_sb_list;
534 struct list_head i_dentry;
535 unsigned long i_ino;
536 atomic_t i_count;
537 unsigned int i_nlink;
538 uid_t i_uid;
539 gid_t i_gid;
540 dev_t i_rdev;
541 unsigned long i_version;
542 loff_t i_size;
543 #ifdef __NEED_I_SIZE_ORDERED
544 seqcount_t i_size_seqcount;
545 #endif
546 struct timespec i_atime;
547 struct timespec i_mtime;
548 struct timespec i_ctime;
549 unsigned int i_blkbits;
550 blkcnt_t i_blocks;
551 unsigned short i_bytes;
552 umode_t i_mode;
553 spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
554 struct mutex i_mutex;
555 struct rw_semaphore i_alloc_sem;
556 const struct inode_operations *i_op;
557 const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
558 struct super_block *i_sb;
559 struct file_lock *i_flock;
560 struct address_space *i_mapping;
561 struct address_space i_data;
562 #ifdef CONFIG_QUOTA
563 struct dquot *i_dquot[MAXQUOTAS];
564 #endif
565 struct list_head i_devices;
566 union {
567 struct pipe_inode_info *i_pipe;
568 struct block_device *i_bdev;
569 struct cdev *i_cdev;
570 };
571 int i_cindex;
572
573 __u32 i_generation;
574
575 #ifdef CONFIG_DNOTIFY
576 unsigned long i_dnotify_mask; /* Directory notify events */
577 struct dnotify_struct *i_dnotify; /* for directory notifications */
578 #endif
579
580 #ifdef CONFIG_INOTIFY
581 struct list_head inotify_watches; /* watches on this inode */
582 struct mutex inotify_mutex; /* protects the watches list */
583 #endif
584
585 unsigned long i_state;
586 unsigned long dirtied_when; /* jiffies of first dirtying */
587
588 unsigned int i_flags;
589
590 atomic_t i_writecount;
591 #ifdef CONFIG_SECURITY
592 void *i_security;
593 #endif
594 void *i_private; /* fs or device private pointer */
595 };
531 struct hlist_node i_hash;
532 struct list_head i_list;
533 struct list_head i_sb_list;
534 struct list_head i_dentry;
535 unsigned long i_ino;
536 atomic_t i_count;
537 unsigned int i_nlink;
538 uid_t i_uid;
539 gid_t i_gid;
540 dev_t i_rdev;
541 unsigned long i_version;
542 loff_t i_size;
543 #ifdef __NEED_I_SIZE_ORDERED
544 seqcount_t i_size_seqcount;
545 #endif
546 struct timespec i_atime;
547 struct timespec i_mtime;
548 struct timespec i_ctime;
549 unsigned int i_blkbits;
550 blkcnt_t i_blocks;
551 unsigned short i_bytes;
552 umode_t i_mode;
553 spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
554 struct mutex i_mutex;
555 struct rw_semaphore i_alloc_sem;
556 const struct inode_operations *i_op;
557 const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
558 struct super_block *i_sb;
559 struct file_lock *i_flock;
560 struct address_space *i_mapping;
561 struct address_space i_data;
562 #ifdef CONFIG_QUOTA
563 struct dquot *i_dquot[MAXQUOTAS];
564 #endif
565 struct list_head i_devices;
566 union {
567 struct pipe_inode_info *i_pipe;
568 struct block_device *i_bdev;
569 struct cdev *i_cdev;
570 };
571 int i_cindex;
572
573 __u32 i_generation;
574
575 #ifdef CONFIG_DNOTIFY
576 unsigned long i_dnotify_mask; /* Directory notify events */
577 struct dnotify_struct *i_dnotify; /* for directory notifications */
578 #endif
579
580 #ifdef CONFIG_INOTIFY
581 struct list_head inotify_watches; /* watches on this inode */
582 struct mutex inotify_mutex; /* protects the watches list */
583 #endif
584
585 unsigned long i_state;
586 unsigned long dirtied_when; /* jiffies of first dirtying */
587
588 unsigned int i_flags;
589
590 atomic_t i_writecount;
591 #ifdef CONFIG_SECURITY
592 void *i_security;
593 #endif
594 void *i_private; /* fs or device private pointer */
595 };
i-node를 통해 파일의 실제 데이타를 제외한 모든 정보를 얻을 수 있다. 일부 파일시스템(FAT, FAT16, FAT32 등등)에 대해서는 struct inode 구조체의 일부 필드가 의미없을 수 도 있다. inode 구조체에서는 실제 inode를 다루는 방법과 파일을 다루는 방법을 위해서 두 가지 구조체를 제공하고 있다.
먼저, inode를 다루는 함수들을 위해서는 struct inode_operations *i_op 필드가 제공된다. 이 구조체는 다음과 같은 형태를 가지고 있다.
1118 struct inode_operations {
1119 int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
1120 struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
1121 int (*link) (struct dentry *,struct inode *,struct dentry *);
1122 int (*unlink) (struct inode *,struct dentry *);
1123 int (*symlink) (struct inode *,struct dentry *,const char *);
1124 int (*mkdir) (struct inode *,struct dentry *,int);
1125 int (*rmdir) (struct inode *,struct dentry *);
1126 int (*mknod) (struct inode *,struct dentry *,int,dev_t);
1127 int (*rename) (struct inode *, struct dentry *,
1128 struct inode *, struct dentry *);
1129 int (*readlink) (struct dentry *, char __user *,int);
1130 void * (*follow_link) (struct dentry *, struct nameidata *);
1131 void (*put_link) (struct dentry *, struct nameidata *, void *);
1132 void (*truncate) (struct inode *);
1133 int (*permission) (struct inode *, int, struct nameidata *);
1134 int (*setattr) (struct dentry *, struct iattr *);
1135 int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
1136 int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
1137 ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
1138 ssize_t (*listxattr) (struct dentry *, char *, size_t);
1139 int (*removexattr) (struct dentry *, const char *);
1140 void (*truncate_range)(struct inode *, loff_t, loff_t);
1141 };
1119 int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
1120 struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
1121 int (*link) (struct dentry *,struct inode *,struct dentry *);
1122 int (*unlink) (struct inode *,struct dentry *);
1123 int (*symlink) (struct inode *,struct dentry *,const char *);
1124 int (*mkdir) (struct inode *,struct dentry *,int);
1125 int (*rmdir) (struct inode *,struct dentry *);
1126 int (*mknod) (struct inode *,struct dentry *,int,dev_t);
1127 int (*rename) (struct inode *, struct dentry *,
1128 struct inode *, struct dentry *);
1129 int (*readlink) (struct dentry *, char __user *,int);
1130 void * (*follow_link) (struct dentry *, struct nameidata *);
1131 void (*put_link) (struct dentry *, struct nameidata *, void *);
1132 void (*truncate) (struct inode *);
1133 int (*permission) (struct inode *, int, struct nameidata *);
1134 int (*setattr) (struct dentry *, struct iattr *);
1135 int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
1136 int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
1137 ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
1138 ssize_t (*listxattr) (struct dentry *, char *, size_t);
1139 int (*removexattr) (struct dentry *, const char *);
1140 void (*truncate_range)(struct inode *, loff_t, loff_t);
1141 };
inode_operations에서는 실제 파일 정보를 만들고 제거하는 다양한 방법을 제공한다.
파일 내용을 다루는 연산을 위해서는 struct file_operations *i_fop 필드가 제공된다. 이 구조체는 다음과 같은 형태를 가지고 있다.
1088 struct file_operations {
1089 struct module *owner;
1090 loff_t (*llseek) (struct file *, loff_t, int);
1091 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
1092 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
1093 ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
1094 ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
1095 int (*readdir) (struct file *, void *, filldir_t);
1096 unsigned int (*poll) (struct file *, struct poll_table_struct *);
1097 int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
1098 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
1099 long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
1100 int (*mmap) (struct file *, struct vm_area_struct *);
1101 int (*open) (struct inode *, struct file *);
1102 int (*flush) (struct file *, fl_owner_t id);
1103 int (*release) (struct inode *, struct file *);
1104 int (*fsync) (struct file *, struct dentry *, int datasync);
1105 int (*aio_fsync) (struct kiocb *, int datasync);
1106 int (*fasync) (int, struct file *, int);
1107 int (*lock) (struct file *, int, struct file_lock *);
1108 ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
1109 ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
1110 unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
1111 int (*check_flags)(int);
1112 int (*dir_notify)(struct file *filp, unsigned long arg);
1113 int (*flock) (struct file *, int, struct file_lock *);
1114 ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
1115 ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
1116 };
1089 struct module *owner;
1090 loff_t (*llseek) (struct file *, loff_t, int);
1091 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
1092 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
1093 ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
1094 ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
1095 int (*readdir) (struct file *, void *, filldir_t);
1096 unsigned int (*poll) (struct file *, struct poll_table_struct *);
1097 int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
1098 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
1099 long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
1100 int (*mmap) (struct file *, struct vm_area_struct *);
1101 int (*open) (struct inode *, struct file *);
1102 int (*flush) (struct file *, fl_owner_t id);
1103 int (*release) (struct inode *, struct file *);
1104 int (*fsync) (struct file *, struct dentry *, int datasync);
1105 int (*aio_fsync) (struct kiocb *, int datasync);
1106 int (*fasync) (int, struct file *, int);
1107 int (*lock) (struct file *, int, struct file_lock *);
1108 ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
1109 ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
1110 unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
1111 int (*check_flags)(int);
1112 int (*dir_notify)(struct file *filp, unsigned long arg);
1113 int (*flock) (struct file *, int, struct file_lock *);
1114 ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
1115 ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
1116 };
파일 시스템을 만드는 것은 결국 이러한 연산자들을 잘 구성하는 것으로 시작한다고 볼 수 있다. 물론, 각각은 실제 물리적인 장치에 어떻게 배치되느냐도 중요하지만, 일단은 이러한 함수들에 내용을 넣는 것부터 시작해 보는 것도 괜찮을 것이다.
아래 코드는 이러한 내용들을 간단히 채워 넣은 파일 시스템 예제 코드로서 아래 주소에서 코드 및 설명을 볼 수 있다.
<참조 위치 : http://www.geocities.com/ravikiran_uvs/articles/rkfs.html>
/**
* Notes:
* Implementing a small filesystem having one file
*
* -> What happens when we mount a file system?
* -> What do we need to provide to the kernel so that we are mountable?
* -> What inode, dentry and file operations do we have to support?
*/
* Notes:
* Implementing a small filesystem having one file
*
* -> What happens when we mount a file system?
* -> What do we need to provide to the kernel so that we are mountable?
* -> What inode, dentry and file operations do we have to support?
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/statfs.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/errno.h>
#include <linux/buffer_head.h>
#include <linux/pagemap.h> /* unlock_page */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/statfs.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/errno.h>
#include <linux/buffer_head.h>
#include <linux/pagemap.h> /* unlock_page */
#define RKFS_MAGIC 0xabcd
#define FILE_INODE_NUMBER 2
#define FILE_INODE_NUMBER 2
/* file_system_type */
/* get_sb */
static struct super_block *
rkfs_get_sb(struct file_system_type *, int, const char *, void *);
/* kill_sb */
static void
rkfs_kill_sb(struct super_block *);
/* get_sb */
static struct super_block *
rkfs_get_sb(struct file_system_type *, int, const char *, void *);
/* kill_sb */
static void
rkfs_kill_sb(struct super_block *);
/* super_operations */
/* read_inode */
static void
rkfs_super_read_inode(struct inode *inode);
/* write_inode */
static int
rkfs_super_write_inode(struct inode *inode, int sync);
/* read_inode */
static void
rkfs_super_read_inode(struct inode *inode);
/* write_inode */
static int
rkfs_super_write_inode(struct inode *inode, int sync);
/* inode_operations */
/* lookup */
static struct dentry *
rkfs_inode_lookup(struct inode *parent_inode, struct dentry *dentry, struct nameidata *);
/* lookup */
static struct dentry *
rkfs_inode_lookup(struct inode *parent_inode, struct dentry *dentry, struct nameidata *);
/* file_operations */
static int
rkfs_file_open (struct inode *, struct file *);
/* readdir */
static int
rkfs_file_readdir(struct file *file, void *dirent, filldir_t filldir);
/* release */
static int
rkfs_file_release (struct inode *, struct file *);
static int
rkfs_file_open (struct inode *, struct file *);
/* readdir */
static int
rkfs_file_readdir(struct file *file, void *dirent, filldir_t filldir);
/* release */
static int
rkfs_file_release (struct inode *, struct file *);
/* Address Space Operations */
/* writepage */
static int
rkfs_writepage(struct page *page, struct writeback_control *wbc);
/* readpage */
static int
rkfs_readpage(struct file *file, struct page *page);
/* prepare_write */
static int
rkfs_prepare_write(struct file *file, struct page *page,
unsigned from, unsigned to);
/* commit_write */
static int
rkfs_commit_write(struct file *file, struct page *page,
unsigned from, unsigned to);
/* writepage */
static int
rkfs_writepage(struct page *page, struct writeback_control *wbc);
/* readpage */
static int
rkfs_readpage(struct file *file, struct page *page);
/* prepare_write */
static int
rkfs_prepare_write(struct file *file, struct page *page,
unsigned from, unsigned to);
/* commit_write */
static int
rkfs_commit_write(struct file *file, struct page *page,
unsigned from, unsigned to);
/* readpage */
/*
* Data declarations
*/
static struct super_operations rkfs_sops = {
read_inode: rkfs_super_read_inode,
statfs: simple_statfs, /* handler from libfs */
write_inode: &rkfs_super_write_inode
};
read_inode: rkfs_super_read_inode,
statfs: simple_statfs, /* handler from libfs */
write_inode: &rkfs_super_write_inode
};
static struct inode_operations rkfs_iops = {
lookup: rkfs_inode_lookup
};
lookup: rkfs_inode_lookup
};
static struct file_operations rkfs_fops = {
open: rkfs_file_open,
read: &generic_file_read,
readdir: &rkfs_file_readdir,
write: &generic_file_write,
release: &rkfs_file_release,
fsync: simple_sync_file
};
open: rkfs_file_open,
read: &generic_file_read,
readdir: &rkfs_file_readdir,
write: &generic_file_write,
release: &rkfs_file_release,
fsync: simple_sync_file
};
static struct file_system_type rkfs = {
name: "rkfs",
get_sb: rkfs_get_sb,
kill_sb: rkfs_kill_sb,
owner: THIS_MODULE
};
name: "rkfs",
get_sb: rkfs_get_sb,
kill_sb: rkfs_kill_sb,
owner: THIS_MODULE
};
static struct address_space_operations rkfs_aops = {
.readpage = rkfs_readpage,
.writepage = rkfs_writepage,
.prepare_write = rkfs_prepare_write,
.commit_write = rkfs_commit_write
};
.readpage = rkfs_readpage,
.writepage = rkfs_writepage,
.prepare_write = rkfs_prepare_write,
.commit_write = rkfs_commit_write
};
static struct inode *rkfs_root_inode;
static char file_buf[PAGE_SIZE] = "Hello World\n";
static int file_size = 12;
static int file_size = 12;
/*
* File-System Operations
*/
* File-System Operations
*/
static int
rkfs_fill_super(struct super_block *sb, void *data, int silent)
{
printk("RKFS: rkfs_fill_super\n" );
sb->s_blocksize = 1024;
sb->s_blocksize_bits = 10;
sb->s_magic = RKFS_MAGIC;
sb->s_op = &rkfs_sops; // super block operations
sb->s_type = &rkfs; // file_system_type
rkfs_fill_super(struct super_block *sb, void *data, int silent)
{
printk("RKFS: rkfs_fill_super\n" );
sb->s_blocksize = 1024;
sb->s_blocksize_bits = 10;
sb->s_magic = RKFS_MAGIC;
sb->s_op = &rkfs_sops; // super block operations
sb->s_type = &rkfs; // file_system_type
rkfs_root_inode = iget(sb, 1); // allocate an inode
rkfs_root_inode->i_op = &rkfs_iops; // set the inode ops
rkfs_root_inode->i_mode = S_IFDIR|S_IRWXU;
rkfs_root_inode->i_fop = &rkfs_fops;
rkfs_root_inode->i_op = &rkfs_iops; // set the inode ops
rkfs_root_inode->i_mode = S_IFDIR|S_IRWXU;
rkfs_root_inode->i_fop = &rkfs_fops;
if(!(sb->s_root = d_alloc_root(rkfs_root_inode))) {
iput(rkfs_root_inode);
return -ENOMEM;
}
iput(rkfs_root_inode);
return -ENOMEM;
}
return 0;
}
}
static struct super_block *
rkfs_get_sb(struct file_system_type *fs_type, int flags, const char *devname, void *data) {
/* rkfs_fill_super this will be called to fill the superblock */
return get_sb_single(
fs_type,
flags,
data,
&rkfs_fill_super);
}
rkfs_get_sb(struct file_system_type *fs_type, int flags, const char *devname, void *data) {
/* rkfs_fill_super this will be called to fill the superblock */
return get_sb_single(
fs_type,
flags,
data,
&rkfs_fill_super);
}
static void
rkfs_kill_sb(struct super_block *super) {
kill_anon_super(super);
}
rkfs_kill_sb(struct super_block *super) {
kill_anon_super(super);
}
/*
* Super-Block Operations
*/
* Super-Block Operations
*/
static void
rkfs_super_read_inode(struct inode *inode) {
printk("RKFS: rkfs_super_read_inode\n");
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_mapping->a_ops = &rkfs_aops;
}
rkfs_super_read_inode(struct inode *inode) {
printk("RKFS: rkfs_super_read_inode\n");
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_mapping->a_ops = &rkfs_aops;
}
static int
rkfs_super_write_inode(struct inode *inode, int wait) {
printk("RKFS: rkfs_super_write_inode (i_ino = %d) = %d\n",
(int)inode->i_ino,
(int)i_size_read(inode));
if(inode->i_ino == FILE_INODE_NUMBER) {
file_size = i_size_read(inode);
}
return 0;
}
rkfs_super_write_inode(struct inode *inode, int wait) {
printk("RKFS: rkfs_super_write_inode (i_ino = %d) = %d\n",
(int)inode->i_ino,
(int)i_size_read(inode));
if(inode->i_ino == FILE_INODE_NUMBER) {
file_size = i_size_read(inode);
}
return 0;
}
/*
* Inode Operations
*/
* Inode Operations
*/
static char filename[] = "hello.txt";
static int filename_len = sizeof(filename) - 1;
static struct dentry *
rkfs_inode_lookup(struct inode *parent_inode, struct dentry *dentry, struct nameidata *nameidata) {
struct inode *file_inode;
printk("RKFS: rkfs_inode_lookup\n");
if(parent_inode->i_ino != rkfs_root_inode->i_ino ||
dentry->d_name.len != filename_len ||
strncmp(dentry->d_name.name, filename, dentry->d_name.len)) {
d_add(dentry, NULL);
goto out;
}
static int filename_len = sizeof(filename) - 1;
static struct dentry *
rkfs_inode_lookup(struct inode *parent_inode, struct dentry *dentry, struct nameidata *nameidata) {
struct inode *file_inode;
printk("RKFS: rkfs_inode_lookup\n");
if(parent_inode->i_ino != rkfs_root_inode->i_ino ||
dentry->d_name.len != filename_len ||
strncmp(dentry->d_name.name, filename, dentry->d_name.len)) {
d_add(dentry, NULL);
goto out;
}
file_inode = iget(parent_inode->i_sb, FILE_INODE_NUMBER);
if(!file_inode)
return ERR_PTR(-EACCES);
file_inode->i_size = file_size;
file_inode->i_mode = S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
file_inode->i_fop = &rkfs_fops;
// file_inode->i_fop
d_add(dentry, file_inode);
if(!file_inode)
return ERR_PTR(-EACCES);
file_inode->i_size = file_size;
file_inode->i_mode = S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
file_inode->i_fop = &rkfs_fops;
// file_inode->i_fop
d_add(dentry, file_inode);
out:
return NULL;
}
return NULL;
}
/*
* File Operations
*/
* File Operations
*/
static int
rkfs_file_open(struct inode *inode, struct file *file) {
printk("RKFS: @rkfs_file_open max_readahead = %d (size = %d)\n", (int)file->f_ra.ra_pages, file_size);
file->f_ra.ra_pages = 0; /* No read-ahead */
return generic_file_open(inode, file);
}
rkfs_file_open(struct inode *inode, struct file *file) {
printk("RKFS: @rkfs_file_open max_readahead = %d (size = %d)\n", (int)file->f_ra.ra_pages, file_size);
file->f_ra.ra_pages = 0; /* No read-ahead */
return generic_file_open(inode, file);
}
static int
rkfs_file_release (struct inode *ino, struct file *file) {
struct dentry *dentry;
dentry = file->f_dentry;
return 0;
}
rkfs_file_release (struct inode *ino, struct file *file) {
struct dentry *dentry;
dentry = file->f_dentry;
return 0;
}
static int
rkfs_file_readdir(struct file *file, void *dirent, filldir_t filldir) {
struct dentry *de = file->f_dentry;
rkfs_file_readdir(struct file *file, void *dirent, filldir_t filldir) {
struct dentry *de = file->f_dentry;
if(file->f_pos > 2)
return 1;
if(filldir(dirent, ".", 1, file->f_pos++, de->d_inode->i_ino, DT_DIR))
return 0;
if(filldir(dirent, "..", 2, file->f_pos++, de->d_parent->d_inode->i_ino, DT_DIR))
return 0;
if(filldir(dirent, filename, filename_len, file->f_pos++, FILE_INODE_NUMBER, DT_REG))
return 0;
return 1;
}
return 1;
if(filldir(dirent, ".", 1, file->f_pos++, de->d_inode->i_ino, DT_DIR))
return 0;
if(filldir(dirent, "..", 2, file->f_pos++, de->d_parent->d_inode->i_ino, DT_DIR))
return 0;
if(filldir(dirent, filename, filename_len, file->f_pos++, FILE_INODE_NUMBER, DT_REG))
return 0;
return 1;
}
/* address_space_operations */
static int
rkfs_writepage(struct page *page, struct writeback_control *wbc) {
void *page_addr = kmap(page);
printk("[RKFS] offset = %d\n", (int)page->index);
printk("RKFS: WritePage: [%s] [%s] [%s] [%s]\n",
PageUptodate(page) ? "Uptodate" : "Not Uptodate",
PageDirty(page) ? "Dirty" : "Not Dirty",
PageWriteback(page) ? "PageWriteback Set" : "PageWriteback Cleared",
PageLocked(page) ? "Locked" : "Unlocked");
memcpy(file_buf, page_addr, PAGE_SIZE);
ClearPageDirty(page);
if(PageLocked(page))
unlock_page(page);
kunmap(page);
return 0;
}
static int
rkfs_writepage(struct page *page, struct writeback_control *wbc) {
void *page_addr = kmap(page);
printk("[RKFS] offset = %d\n", (int)page->index);
printk("RKFS: WritePage: [%s] [%s] [%s] [%s]\n",
PageUptodate(page) ? "Uptodate" : "Not Uptodate",
PageDirty(page) ? "Dirty" : "Not Dirty",
PageWriteback(page) ? "PageWriteback Set" : "PageWriteback Cleared",
PageLocked(page) ? "Locked" : "Unlocked");
memcpy(file_buf, page_addr, PAGE_SIZE);
ClearPageDirty(page);
if(PageLocked(page))
unlock_page(page);
kunmap(page);
return 0;
}
static int
rkfs_readpage(struct file *file, struct page *page) {
void *page_addr;
printk("RKFS: readpage called for page index=[%d]\n", (int)page->index);
if(page->index > 0) {
return -ENOSPC;
}
rkfs_readpage(struct file *file, struct page *page) {
void *page_addr;
printk("RKFS: readpage called for page index=[%d]\n", (int)page->index);
if(page->index > 0) {
return -ENOSPC;
}
printk("RKFS: Page: [%s] [%s] [%s] [%s]\n",
PageUptodate(page) ? "Uptodate" : "Not Uptodate",
PageDirty(page) ? "Dirty" : "Not Dirty",
PageWriteback(page) ? "PageWriteback Set" : "PageWriteback Cleared",
PageLocked(page) ? "Locked" : "Unlocked");
SetPageUptodate(page);
page_addr = kmap(page);
if(page_addr)
memcpy(page_addr, file_buf, PAGE_SIZE);
if(PageLocked(page))
unlock_page(page);
kunmap(page);
return 0;
}
PageUptodate(page) ? "Uptodate" : "Not Uptodate",
PageDirty(page) ? "Dirty" : "Not Dirty",
PageWriteback(page) ? "PageWriteback Set" : "PageWriteback Cleared",
PageLocked(page) ? "Locked" : "Unlocked");
SetPageUptodate(page);
page_addr = kmap(page);
if(page_addr)
memcpy(page_addr, file_buf, PAGE_SIZE);
if(PageLocked(page))
unlock_page(page);
kunmap(page);
return 0;
}
static int
rkfs_prepare_write(struct file *file, struct page *page,
unsigned from, unsigned to) {
return 0;
}
rkfs_prepare_write(struct file *file, struct page *page,
unsigned from, unsigned to) {
return 0;
}
/* modified from generic_commit_write. generic_commit_write calls the
* block device layer to write set up buffer heads for I/O.
*/
static int
rkfs_commit_write(struct file *file, struct page *page,
unsigned from, unsigned to) {
struct inode *inode = page->mapping->host;
void *page_addr = kmap(page);
loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
* block device layer to write set up buffer heads for I/O.
*/
static int
rkfs_commit_write(struct file *file, struct page *page,
unsigned from, unsigned to) {
struct inode *inode = page->mapping->host;
void *page_addr = kmap(page);
loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
printk("RKFS: commit_write: [%s] [%s] [%s] \n",
PageUptodate(page) ? "Uptodate" : "Not Uptodate",
PageDirty(page) ? "Dirty" : "Not Dirty",
PageLocked(page) ? "Locked" : "Unlocked");
PageUptodate(page) ? "Uptodate" : "Not Uptodate",
PageDirty(page) ? "Dirty" : "Not Dirty",
PageLocked(page) ? "Locked" : "Unlocked");
if(page->index == 0) {
memcpy(file_buf, page_addr, PAGE_SIZE);
ClearPageDirty(page);
}
memcpy(file_buf, page_addr, PAGE_SIZE);
ClearPageDirty(page);
}
SetPageUptodate(page);
kunmap(page);
/*
* No need to use i_size_read() here, the i_size
* cannot change under us because we hold i_sem.
*/
if (pos > inode->i_size) {
i_size_write(inode, pos);
mark_inode_dirty(inode);
}
kunmap(page);
/*
* No need to use i_size_read() here, the i_size
* cannot change under us because we hold i_sem.
*/
if (pos > inode->i_size) {
i_size_write(inode, pos);
mark_inode_dirty(inode);
}
return 0;
}
static int
rkfs_init_module(void) {
int err;
err = register_filesystem(&rkfs);
return err;
}
return err;
}
static void
rkfs_cleanup_module(void) {
unregister_filesystem(&rkfs);
}
rkfs_cleanup_module(void) {
unregister_filesystem(&rkfs);
}
module_init(rkfs_init_module);
module_exit(rkfs_cleanup_module);
module_exit(rkfs_cleanup_module);
MODULE_LICENSE("GPL");
다음번부터는 실제 파일 시스템들을 하나씩 들쳐볼까 한다. 여러모로 어려운 부분이 있겠지만, 실제 파일 시스템을 살펴보는 것이 제일 좋은 방법이라 생각된다.
'Linux > Filesystem' 카테고리의 다른 글
| HAMMER 파일 시스템 (0) | 2007/12/06 |
|---|---|
| FUSE 파일 시스템 Overview (0) | 2007/11/12 |
| 파일 시스템의 주요 구조체들 (0) | 2007/11/12 |
| 파일 시스템 등록과 해지에 관련된 함수 살펴보기 (0) | 2007/11/09 |
TAG filesystem
이올린에 북마크하기
이올린에 추천하기

