2024年02月07日 情報科学類 オペレーティングシステム II 筑波大学 システム情報系 新城 靖 <yas@cs.tsukuba.ac.jp>
このページは、次の URL にあります。
https://www.coins.tsukuba.ac.jp/~yas/coins/os2-2023/2024-02-07
あるいは、次のページから手繰っていくこともできます。
https://www.coins.tsukuba.ac.jp/~yas/
https://www.cs.tsukuba.ac.jp/~yas/
試験について
Linux では、割り込みの処理を2つに分ける。
図? 割り込み処理の前半部分と後半部分
割り込みハンドラ(前半部)と後半部の役割分担の目安。
注意1: Tasklet は、task 構造体とはまったく関係ない。名前がよくない。
注意2: Softirq という用語を、割り込み処理の後半部という意味で使う人もい る。
注意3: 伝統的なUnixでは、top half は、システム・コールから派生する上位 層の処理、bottom half は、割り込みから派生する下位層の処理の意味で使わ れることがある。Linux では、top half, bottom half は、割り込み処理の前 半部分と後半部分の意味に使う。
Tasklet で1つの仕事は次のような、struct tasklet_struct で表現される。
linux-6.6.9/include/linux/interrupt.h 642: struct tasklet_struct 643: { 644: struct tasklet_struct *next; 645: unsigned long state; 646: atomic_t count; 647: bool use_callback; 648: union { 649: void (*func)(unsigned long data); 650: void (*callback)(struct tasklet_struct *t); 651: }; 652: unsigned long data; 653: };
図? Taskletにおける仕事のキュー
DECLARE_TASKLET(name, func) 有効な(count==0) の struct tasklet_struct を宣言する DECLARE_TASKLET_DISABLED(name, func) 無効な(count==1) の struct tasklet_struct を宣言する
void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data); void tasklet_setup(struct tasklet_struct *t, void (*callback)(struct tasklet_struct *))その他に、生成消滅有効無効に関して次のような操作がある。
void tasklet_handler(unsigned long data) { ... }tasklet_setup() 等の場合、Tasklet のハンドラは、次のような関数である。 struct tasklet_struct * が渡される。 struct timer_listで示した例 や 後述する EXT4_I()と同様に、 container_of() で外側の構造体を取り出す。
void tasklet_handler(struct tasklet_struct *t) { ... }
void tasklet_schedule(struct tasklet_struct *t) Tasklet t を通常の優先度でスケジュールする void tasklet_hi_schedule(struct tasklet_struct *t) Tasklet t を高優先度でスケジュールするすると、それは「そのうちに」1度だけ実行される。
linux-6.6.9/drivers/net/wireless/ath/ath11k/ce.h 167: struct ath11k_ce_pipe { ... 177: struct tasklet_struct intr_tq; ... 182: }; linux-6.6.9/drivers/net/wireless/ath/ath11k/pcic.c 616: int ath11k_pcic_config_irq(struct ath11k_base *ab) 617: { 618: struct ath11k_ce_pipe *ce_pipe; ... 645: ce_pipe = &ab->ce.ce_pipe[i]; 646: 647: irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 648: 649: tasklet_setup(&ce_pipe->intr_tq, ath11k_pcic_ce_tasklet); ... 650: 651: ret = request_irq(irq, ath11k_pcic_ce_interrupt_handler, 652: irq_flags, irq_name[irq_idx], ce_pipe); ... 670: }
linux-6.6.9/drivers/net/wireless/ath/ath11k/pcic.c 391: static irqreturn_t ath11k_pcic_ce_interrupt_handler(int irq, void *arg) 392: { 393: struct ath11k_ce_pipe *ce_pipe = arg; 394: struct ath11k_base *ab = ce_pipe->ab; 395: int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; 396: 397: if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) 398: return IRQ_HANDLED; 399: 400: /* last interrupt received for this CE */ 401: ce_pipe->timestamp = jiffies; 402: 403: disable_irq_nosync(ab->irq_num[irq_idx]); 404: 405: tasklet_schedule(&ce_pipe->intr_tq); 406: 407: return IRQ_HANDLED; 408: } 381: static void ath11k_pcic_ce_tasklet(struct tasklet_struct *t) 382: { 383: struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); 384: int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; 385: 386: ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); 387: 388: enable_irq(ce_pipe->ab->irq_num[irq_idx]); 389: } linux-6.6.9/include/linux/interrupt.h 669: #define from_tasklet(var, callback_tasklet, tasklet_fieldname) \ 670: container_of(callback_tasklet, typeof(*var), tasklet_fieldname)
図? Work Queueにおける仕事のキュー
キューにつながれる仕事は、Tasklet の仕事とほとんど同じで、関数へのポイ ンタ func と data からなる。処理の主体が、ワーカ・スレッドと呼ばれるカー ネル・レベルのスレッドである所が違う。
汎用の Work Queue デフォルトのワーカ・スレッドは、kworker/n (nはプロセッ サ番号) とよばれ、プロセッサごとに作られる。1つのスレッドで、様々な要 求元の仕事をこなす。下の例では、1つのプロセッサに4個のスレッドが 作られている。そのうち2つは、nice 値が -20 で高優先度。
$ ps alx | grep worker | wc
23 301 2310
$ ps alx | grep 'worker.*/0'
1 0 59 2 0 -20 0 0 - I< ? 0:00 [kworker/0:1H-kblockd]
1 0 759 2 0 -20 0 0 - I< ? 0:00 [kworker/0:2H-kblockd]
1 0 293655 2 20 0 0 0 - I ? 0:00 [kworker/0:1-cgroup_destroy]
1 0 294240 2 20 0 0 0 - I ? 0:00 [kworker/0:2-mm_percpu_wq]
0 1013 294551 292317 20 0 9220 1156 - S+ pts/1 0:00 grep worker.*/0
$ ps alx | grep 'worker.*/0'
1 0 59 2 0 -20 0 0 - I< ? 0:00 [kworker/0:1H-kblockd]
1 0 759 2 0 -20 0 0 - I< ? 0:00 [kworker/0:2H-kblockd]
1 0 293655 2 20 0 0 0 - I ? 0:00 [kworker/0:1-cgroup_destroy]
1 0 294240 2 20 0 0 0 - I ? 0:00 [kworker/0:2-events]
0 1013 294554 292317 20 0 9220 1208 - S+ pts/1 0:00 grep worker.*/0
$ ps alx | head -1
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
$
汎用の Work Queue のワーカ・スレッドの他に、専用のワーカ・スレッドを作
ることもできる。
linux-6.6.9/include/linux/workqueue.h 21: typedef void (*work_func_t)(struct work_struct *work); 98: struct work_struct { 99: atomic_long_t data; 100: struct list_head entry; 101: work_func_t func; ... 105: }; linux-6.6.9/include/linux/types.h 190: struct list_head { 191: struct list_head *next, *prev; 192: };
struct work_struct my_work; ... INIT_WORK(&my_work,my_work_handler);
void my_work_handler(struct work_struct *work) { ... }
schedule_work(&work);この結果、INIT_WORK() で設定したハンドラがワーカ・スレッドにより「その うち」に呼び出される。
schedule_work() では、即座に実行される可能性もある。少し後に実行したい (間を取りたい)時には、次の関数を呼ぶ。
schedule_delayed_work(&work, ticks);ticks は、どのくらい間をとるか。単位は、 ticks (jiffiesの単位)。 多くのシステムで10ミリ秒-1ミリ秒で、設定によって異なる。
linux-6.6.9/arch/x86/include/asm/mc146818rtc.h 101: #define RTC_IRQ 8 linux-6.6.9/drivers/rtc/rtc-cmos.c 73: struct cmos_rtc { 74: struct rtc_device *rtc; 75: struct device *dev; 76: int irq; .... 92: }; 697: static struct cmos_rtc cmos_rtc; 920: static int INITSECTION 921: cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) 922: { ... 1020: cmos_rtc.rtc = devm_rtc_allocate_device(dev); ... 1077: rtc_cmos_int_handler = hpet_rtc_interrupt; ... 1088: retval = request_irq(rtc_irq, rtc_cmos_int_handler, 1089: 0, dev_name(&cmos_rtc.rtc->dev), 1090: cmos_rtc.rtc); ... 1101: retval = devm_rtc_register_device(cmos_rtc.rtc); ... 1141: } 699: static irqreturn_t cmos_interrupt(int irq, void *p) 700: { 701: u8 irqstat; ... 713: irqstat = CMOS_READ(RTC_INTR_FLAGS); ... 740: if (is_intr(irqstat)) { 741: rtc_update_irq(p, 1, irqstat); 742: return IRQ_HANDLED; 743: } else 744: return IRQ_NONE; 745: }以下、追加。
linux-6.6.9/include/linux/rtc.h 87: struct rtc_device { ... 112: struct work_struct irqwork; ... 164: }; linux-6.6.9/drivers/rtc/class.c 203: static struct rtc_device *rtc_allocate_device(void) 204: { 205: struct rtc_device *rtc; 206: 207: rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); ... 233: INIT_WORK(&rtc->irqwork, rtc_timer_do_work); ... 246: return rtc; 247: } linux-6.6.9/drivers/rtc/interface.c 900: void rtc_timer_do_work(struct work_struct *work) 901: { ... 966: } 683: void rtc_update_irq(struct rtc_device *rtc, 684: unsigned long num, unsigned long events) 685: { ... 690: schedule_work(&rtc->irqwork); 691: }
解決策:
図? 層構造を用いたファイル・システムの実装
解決策
$ ls -l /usr/bin/perl{,5.26.3}
-rwxr-xr-x 2 root root 12752 Jan 18 2023 /usr/bin/perl
-rwxr-xr-x 2 root root 12752 Jan 18 2023 /usr/bin/perl5.26.3
$ ls -il /usr/bin/perl{,5.26.3}
403909688 -rwxr-xr-x 2 root root 12752 Jan 18 2023 /usr/bin/perl
403909688 -rwxr-xr-x 2 root root 12752 Jan 18 2023 /usr/bin/perl5.26.3
$
$ grep -v '#' /etc/fstab
UUID=9cfbc67e-781c-48d1-8303-1dde8ce87ee9 / ext4 defaults 1 1
UUID=bab1faf1-5f5b-4a2a-b24f-e850a2b0b82d /boot ext4 defaults 1 2
UUID=a1f61ff2-2c99-4c54-8c3e-2178eed3ec10 swap swap defaults 0 0
tmpfs /dev/shm tmpfs defaults 0 0
devpts /dev/pts devpts gid=5,mode=620 0 0
sysfs /sys sysfs defaults 0 0
proc /proc proc defaults 0 0
pentas-fs:/vol0/home /home nfs rw,hard,bg,nfsvers=3,intr 0 0
pentas-fs:/vol0/web /var/www nfs rw,hard,bg,nfsvers=3,intr 0 0
pentas-fs:/vol0/local3 /usr/local3 nfs rw,hard,bg,nfsvers=3,intr 0 0
$ df /
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda3 49071944 6721604 39857568 15% /
$ blkid /dev/sda3
/dev/sda3: UUID="9cfbc67e-781c-48d1-8303-1dde8ce87ee9" TYPE="ext4"
$ ls -l /dev/sda3
brw-rw----. 1 root disk 8, 3 Feb 2 10:50 /dev/sda3
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 50G 0 disk
|-sda1 8:1 0 512M 0 part /boot
|-sda2 8:2 0 2G 0 part [SWAP]
`-sda3 8:3 0 47.6G 0 part /
sr0 11:0 1 1024M 0 rom
$ ls -l /dev/sda
brw-rw----. 1 root disk 8, 0 Feb 2 10:50 /dev/sda
$
$ grep cd /etc/auto.misc
cd -fstype=iso9660,ro,nosuid,nodev :/dev/cdrom
$
STAT(2) Linux Programmer's Manual STAT(2) ... int stat(const char *path, struct stat *buf); ... struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ mode_t st_mode; /* protection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; /* device ID (if special file) */ off_t st_size; /* total size, in bytes */ blksize_t st_blksize; /* blocksize for filesystem I/O */ blkcnt_t st_blocks; /* number of blocks allocated */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last status change */ };stat コマンドを使うと stat システム・コールで返される値に近いものが表示 される。
$ stat .bashrc
File: .bashrc
Size: 181 Blocks: 9 IO Block: 1048576 regular file
Device: 38h/56d Inode: 28759903 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1013/ yas) Gid: ( 5510/ prof)
Access: 2024-02-01 22:12:30.143693000 +0900
Modify: 2023-05-16 14:42:05.705198901 +0900
Change: 2023-05-16 14:42:05.705198901 +0900
Birth: -
$
図? スーパーブロック、inode、dentry、file
int fd1 = open("file1",O_RDONLY); int fd2 = open("file1",O_RDONLY);ファイル名 "file1" で表現されるファイルの inode 構造体は、1 個でも、 file 構造体は、2 個割り当てられる。
ディスク上には対応するデータ構造は存在しない。
linux-6.6.9/include/linux/fs.h 992: struct file { ... 1004: fmode_t f_mode; 1005: atomic_long_t f_count; ... 1007: loff_t f_pos; ... 1012: struct path f_path; 1013: struct inode *f_inode; /* cached value */ 1014: const struct file_operations *f_op; ... 1021: void *private_data; ... 1027: struct address_space *f_mapping; ... 1030: } __randomize_layout 1031: __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */ linux-6.6.9/include/linux/path.h 8: struct path { 9: struct vfsmount *mnt; 10: struct dentry *dentry; 11: } __randomize_layout;
図? 方法1
図? 方法2
図? 方法3
struct fileの操作は、たとえば次のような形で行われる。 第1引数は、struct file *。
struct file *file; file->f_op->read(file, buf, count, pos);f_op には、次のような手続きがある。各ファイルシステム (ext4,nfs,tmpfs,...) ごとに、手続きの実体は異なるが、インタフェースは同じ。
再掲
linux-6.6.9/include/linux/fs.h 1852: struct file_operations { 1853: struct module *owner; 1854: loff_t (*llseek) (struct file *, loff_t, int); 1855: ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); 1856: ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); 1857: ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); 1858: ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); 1859: int (*iopoll)(struct kiocb *kiocb, struct io_comp_batch *, 1860: unsigned int flags); 1861: int (*iterate_shared) (struct file *, struct dir_context *); 1862: __poll_t (*poll) (struct file *, struct poll_table_struct *); 1863: long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); 1864: long (*compat_ioctl) (struct file *, unsigned int, unsigned long); 1865: int (*mmap) (struct file *, struct vm_area_struct *); 1866: unsigned long mmap_supported_flags; 1867: int (*open) (struct inode *, struct file *); 1868: int (*flush) (struct file *, fl_owner_t id); 1869: int (*release) (struct inode *, struct file *); 1870: int (*fsync) (struct file *, loff_t, loff_t, int datasync); 1871: int (*fasync) (int, struct file *, int); 1872: int (*lock) (struct file *, int, struct file_lock *); 1873: unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); 1874: int (*check_flags)(int); 1875: int (*flock) (struct file *, int, struct file_lock *); 1876: ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); 1877: ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); 1878: void (*splice_eof)(struct file *file); 1879: int (*setlease)(struct file *, int, struct file_lock **, void **); 1880: long (*fallocate)(struct file *file, int mode, loff_t offset, 1881: loff_t len); 1882: void (*show_fdinfo)(struct seq_file *m, struct file *f); 1883: #ifndef CONFIG_MMU 1884: unsigned (*mmap_capabilities)(struct file *); 1885: #endif 1886: ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, 1887: loff_t, size_t, unsigned int); 1888: loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in, 1889: struct file *file_out, loff_t pos_out, 1890: loff_t len, unsigned int remap_flags); 1891: int (*fadvise)(struct file *, loff_t, loff_t, int); 1892: int (*uring_cmd)(struct io_uring_cmd *ioucmd, unsigned int issue_flags); 1893: int (*uring_cmd_iopoll)(struct io_uring_cmd *, struct io_comp_batch *, 1894: unsigned int poll_flags); 1895: } __randomize_layout;主な手続きの意味
linux-6.6.9/include/linux/dcache.h 82: struct dentry { ... 87: struct dentry *d_parent; /* parent directory */ 88: struct qstr d_name; 89: struct inode *d_inode; /* Where the name belongs to - NULL is 90: * negative */ 91: unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */ ... 94: struct lockref d_lockref; /* per-dentry lock and refcount */ 95: const struct dentry_operations *d_op; 96: struct super_block *d_sb; /* The root of the dentry tree */ ... 98: void *d_fsdata; /* fs-specific data */ ... 104: struct list_head d_child; /* child of parent list */ 105: struct list_head d_subdirs; /* our children */ ... 114: } __randomize_layout; 283: static inline unsigned d_count(const struct dentry *dentry) 284: { 285: return dentry->d_lockref.count; 286: } 35: #define HASH_LEN_DECLARE u32 hash; u32 len 49: struct qstr { 50: union { 51: struct { 52: HASH_LEN_DECLARE; 53: }; 54: u64 hash_len; 55: }; 56: const unsigned char *name; 57: }; 71: # define DNAME_INLINE_LEN 32 /* 192 bytes */
linux-6.6.9/include/linux/fs.h 639: struct inode { 640: umode_t i_mode; 641: unsigned short i_opflags; 642: kuid_t i_uid; 643: kgid_t i_gid; ... 651: const struct inode_operations *i_op; 652: struct super_block *i_sb; ... 660: unsigned long i_ino; ... 669: const unsigned int i_nlink; ... 672: dev_t i_rdev; 673: loff_t i_size; 674: struct timespec64 i_atime; 675: struct timespec64 i_mtime; 676: struct timespec64 __i_ctime; /* use inode_*_ctime accessors! */ 677: spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ 678: unsigned short i_bytes; 679: u8 i_blkbits; 680: u8 i_write_hint; 681: blkcnt_t i_blocks; ... 694: struct hlist_node i_hash; ... 708: struct hlist_head i_dentry; ... 713: atomic_t i_count; ... 748: void *i_private; /* fs or device private pointer */ 749: } __randomize_layout;
struct inode *inode; ... inode->i_op->create(idmap, inode, name, mode, true);i_op には、次のような手続きがある。各ファイルシステム (ext4,nfs,tmpfs,...) ごとに、手続きの実体は異なるが、インタフェースは同じ。
1904: struct inode_operations { 1905: struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int); 1906: const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *); 1907: int (*permission) (struct mnt_idmap *, struct inode *, int); 1908: struct posix_acl * (*get_inode_acl)(struct inode *, int, bool); 1909: 1910: int (*readlink) (struct dentry *, char __user *,int); 1911: 1912: int (*create) (struct mnt_idmap *, struct inode *,struct dentry *, 1913: umode_t, bool); 1914: int (*link) (struct dentry *,struct inode *,struct dentry *); 1915: int (*unlink) (struct inode *,struct dentry *); 1916: int (*symlink) (struct mnt_idmap *, struct inode *,struct dentry *, 1917: const char *); 1918: int (*mkdir) (struct mnt_idmap *, struct inode *,struct dentry *, 1919: umode_t); 1920: int (*rmdir) (struct inode *,struct dentry *); 1921: int (*mknod) (struct mnt_idmap *, struct inode *,struct dentry *, 1922: umode_t,dev_t); 1923: int (*rename) (struct mnt_idmap *, struct inode *, struct dentry *, 1924: struct inode *, struct dentry *, unsigned int); 1925: int (*setattr) (struct mnt_idmap *, struct dentry *, struct iattr *); 1926: int (*getattr) (struct mnt_idmap *, const struct path *, 1927: struct kstat *, u32, unsigned int); 1928: ssize_t (*listxattr) (struct dentry *, char *, size_t); 1929: int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, 1930: u64 len); 1931: int (*update_time)(struct inode *, int); 1932: int (*atomic_open)(struct inode *, struct dentry *, 1933: struct file *, unsigned open_flag, 1934: umode_t create_mode); 1935: int (*tmpfile) (struct mnt_idmap *, struct inode *, 1936: struct file *, umode_t); 1937: struct posix_acl *(*get_acl)(struct mnt_idmap *, struct dentry *, 1938: int); 1939: int (*set_acl)(struct mnt_idmap *, struct dentry *, 1940: struct posix_acl *, int); 1941: int (*fileattr_set)(struct mnt_idmap *idmap, 1942: struct dentry *dentry, struct fileattr *fa); 1943: int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa); 1944: struct offset_ctx *(*get_offset_ctx)(struct inode *inode); 1945: } ____cacheline_aligned;
linux-6.6.9/include/linux/fs.h 1188: struct super_block { ... 1193: loff_t s_maxbytes; /* Max file size */ ... 1195: const struct super_operations *s_op; ... 1237: void *s_fs_info; /* Filesystem private info */ ... 1301: struct list_lru s_dentry_lru; 1302: struct list_lru s_inode_lru; ... 1315: struct list_head s_inodes; /* all inodes */ ... 1319: } __randomize_layout;
struct super_block *sh; ... sh->s_op->write_super(sb);
linux-6.6.9/include/linux/fs.h 1995: struct super_operations { 1996: struct inode *(*alloc_inode)(struct super_block *sb); 1997: void (*destroy_inode)(struct inode *); 1998: void (*free_inode)(struct inode *); 1999: 2000: void (*dirty_inode) (struct inode *, int flags); 2001: int (*write_inode) (struct inode *, struct writeback_control *wbc); 2002: int (*drop_inode) (struct inode *); 2003: void (*evict_inode) (struct inode *); 2004: void (*put_super) (struct super_block *); 2005: int (*sync_fs)(struct super_block *sb, int wait); 2006: int (*freeze_super) (struct super_block *, enum freeze_holder who); 2007: int (*freeze_fs) (struct super_block *); 2008: int (*thaw_super) (struct super_block *, enum freeze_holder who); 2009: int (*unfreeze_fs) (struct super_block *); 2010: int (*statfs) (struct dentry *, struct kstatfs *); 2011: int (*remount_fs) (struct super_block *, int *, char *); 2012: void (*umount_begin) (struct super_block *); 2013: 2014: int (*show_options)(struct seq_file *, struct dentry *); 2015: int (*show_devname)(struct seq_file *, struct dentry *); 2016: int (*show_path)(struct seq_file *, struct dentry *); 2017: int (*show_stats)(struct seq_file *, struct dentry *); 2018: #ifdef CONFIG_QUOTA 2019: ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); 2020: ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); 2021: struct dquot **(*get_dquots)(struct inode *); 2022: #endif 2023: long (*nr_cached_objects)(struct super_block *, 2024: struct shrink_control *); 2025: long (*free_cached_objects)(struct super_block *, 2026: struct shrink_control *); 2027: void (*shutdown)(struct super_block *sb); 2028: };
p->files->fdt->fd[fd]
の struct file を表
す。開いているファイルの数が小さい時は、
p->files->fd_array[fd]
と同じ。
多くのファイルを開くプロセスでは、
p->files->fd_array[NR_OPEN_DEFAULT]
で足りなくなった時は、
expand_files(), expand_fdtable() で拡張する。
これらの関数では、kmalloc() 等でメモリを割り当てる。
linux-6.6.9/include/linux/sched.h 743: struct task_struct { ... 1094: struct files_struct *files; ... 1554: }; linux-6.6.9/include/linux/fdtable.h 24: #define NR_OPEN_DEFAULT BITS_PER_LONG 49: struct files_struct { ... 57: struct fdtable __rcu *fdt; 58: struct fdtable fdtab; ... 67: struct file __rcu * fd_array[NR_OPEN_DEFAULT]; 68: }; 27: struct fdtable { ... 29: struct file __rcu **fd; /* current fd array */ ... 34: }; linux-6.6.9/include/asm-generic/bitsperlong.h 8: #ifdef CONFIG_64BIT 9: #define BITS_PER_LONG 64 10: #else 11: #define BITS_PER_LONG 32 12: #endif /* CONFIG_64BIT */
図? task_struct、ファイル記述子、file構造体、その他
linux-6.6.9/fs/read_write.c 621: SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) 622: { 623: return ksys_read(fd, buf, count); 624: } 602: ssize_t ksys_read(unsigned int fd, char __user *buf, size_t count) 603: { 604: struct fd f = fdget_pos(fd); 605: ssize_t ret = -EBADF; 606: 607: if (f.file) { 608: loff_t pos, *ppos = file_ppos(f.file); 609: if (ppos) { 610: pos = *ppos; 611: ppos = &pos; 612: } 613: ret = vfs_read(f.file, buf, count, ppos); 614: if (ret >= 0 && ppos) 615: f.file->f_pos = pos; 616: fdput_pos(f); 617: } 618: return ret; 619: } linux-6.6.9/include/linux/file.h 36: struct fd { 37: struct file *file; 38: unsigned int flags; 39: };
linux-6.6.9/fs/read_write.c 450: ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) 451: { 452: ssize_t ret; 453: 454: if (!(file->f_mode & FMODE_READ)) 455: return -EBADF; 456: if (!(file->f_mode & FMODE_CAN_READ)) 457: return -EINVAL; 458: if (unlikely(!access_ok(buf, count))) 459: return -EFAULT; 460: 461: ret = rw_verify_area(READ, file, pos, count); 462: if (ret) 463: return ret; 464: if (count > MAX_RW_COUNT) 465: count = MAX_RW_COUNT; 466: 467: if (file->f_op->read) 468: ret = file->f_op->read(file, buf, count, pos); 469: else if (file->f_op->read_iter) 470: ret = new_sync_read(file, buf, count, pos); 471: else 472: ret = -EINVAL; 473: if (ret > 0) { 474: fsnotify_access(file); 475: add_rchar(current, ret); 476: } 477: inc_syscr(current); 478: return ret; 479: } 379: static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) 380: { 381: struct kiocb kiocb; 382: struct iov_iter iter; 383: ssize_t ret; 384: 385: init_sync_kiocb(&kiocb, filp); 386: kiocb.ki_pos = (ppos ? *ppos : 0); 387: iov_iter_ubuf(&iter, ITER_DEST, buf, len); 388: 389: ret = call_read_iter(filp, &kiocb, &iter); 390: BUG_ON(ret == -EIOCBQUEUED); 391: if (ppos) 392: *ppos = kiocb.ki_pos; 393: return ret; 394: } linux-6.6.9/include/linux/fs.h 1947: static inline ssize_t call_read_iter(struct file *file, struct kiocb *kio, 1948: struct iov_iter *iter) 1949: { 1950: return file->f_op->read_iter(kio, iter); 1951: }vfs_read() は、次のように最終的には file->f_op->read() か file->f_op->read_iter() を呼び出す。
linux-6.6.9/fs/ext4/file.c 931: const struct file_operations ext4_file_operations = { 932: .llseek = ext4_llseek, 933: .read_iter = ext4_file_read_iter, 934: .write_iter = ext4_file_write_iter, 935: .iopoll = iocb_bio_iopoll, 936: .unlocked_ioctl = ext4_ioctl, 937: #ifdef CONFIG_COMPAT 938: .compat_ioctl = ext4_compat_ioctl, 939: #endif 940: .mmap = ext4_file_mmap, 941: .mmap_supported_flags = MAP_SYNC, 942: .open = ext4_file_open, 943: .release = ext4_release_file, 944: .fsync = ext4_sync_file, 945: .get_unmapped_area = thp_get_unmapped_area, 946: .splice_read = ext4_file_splice_read, 947: .splice_write = iter_file_splice_write, 948: .fallocate = ext4_fallocate, 949: }; 950: 951: const struct inode_operations ext4_file_inode_operations = { 952: .setattr = ext4_setattr, 953: .getattr = ext4_file_getattr, ... 960: }; linux-6.6.9/fs/ext4/super.c 1627: static const struct super_operations ext4_sops = { 1628: .alloc_inode = ext4_alloc_inode, 1629: .free_inode = ext4_free_in_core_inode, ... 1647: };
linux-6.6.9/fs/ext4/ext4.h 992: struct ext4_inode_info { ... 1081: struct inode vfs_inode; ... 1156: }; 1749: static inline struct ext4_inode_info *EXT4_I(struct inode *inode) 1750: { 1751: return container_of(inode, struct ext4_inode_info, vfs_inode); 1752: }
図? Ext4 ファイルシステムで使う構造体 ext4_inode_info での struct inode の保持
linux-6.6.9/fs/ext4/file.c 130: static ssize_t ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to) 131: { ... 147: return generic_file_read_iter(iocb, to); 148: }
linux-6.6.9/mm/filemap.c 2789: ssize_t 2790: generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) 2791: { ... 2831: return filemap_read(iocb, iter, retval); 2832: }
linux-6.6.9/include/linux/mm_types.h 293: struct folio { ... 323: struct page page; ... 361: }; linux-6.6.9/include/linux/pagevec.h 28: struct folio_batch { 29: unsigned char nr; 30: bool percpu_pvec_drained; 31: struct folio *folios[PAGEVEC_SIZE]; 32: }; linux-6.6.9/mm/filemap.c 2617: ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter, 2618: ssize_t already_read) 2619: { 2620: struct file *filp = iocb->ki_filp; 2621: struct file_ra_state *ra = &filp->f_ra; 2622: struct address_space *mapping = filp->f_mapping; 2623: struct inode *inode = mapping->host; 2624: struct folio_batch fbatch; 2625: int i, error = 0; 2626: bool writably_mapped; 2627: loff_t isize, end_offset; ... 2636: folio_batch_init(&fbatch); 2637: 2638: do { ... 2652: error = filemap_get_pages(iocb, iter->count, &fbatch, false); ... 2683: for (i = 0; i < folio_batch_count(&fbatch); i++) { 2684: struct folio *folio = fbatch.folios[i]; ... 2703: copied = copy_folio_to_iter(folio, offset, bytes, iter); 2704: 2705: already_read += copied; 2706: iocb->ki_pos += copied; 2707: last_pos = iocb->ki_pos; ... 2713: } ... 2717: folio_batch_init(&fbatch); 2718: } while (iov_iter_count(iter) && iocb->ki_pos < isize && !error); ... 2722: return already_read ? already_read : error; 2723: } linux-6.6.9/include/linux/uio.h 182: static inline size_t copy_folio_to_iter(struct folio *folio, size_t offset, 183: size_t bytes, struct iov_iter *i) 184: { 185: return copy_page_to_iter(&folio->page, offset, bytes, i); 186: }
linux-6.6.9/fs/namei.c 4162: SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode) 4163: { 4164: return do_mkdirat(AT_FDCWD, getname(pathname), mode); 4165: } 4157: SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode) 4158: { 4159: return do_mkdirat(dfd, getname(pathname), mode); 4160: } 4161: 4128: int do_mkdirat(int dfd, struct filename *name, umode_t mode) 4129: { 4130: struct dentry *dentry; 4131: struct path path; 4132: int error; 4133: unsigned int lookup_flags = LOOKUP_DIRECTORY; 4134: 4135: retry: 4136: dentry = filename_create(dfd, name, &path, lookup_flags); ... 4144: error = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode, 4145: dentry, mode); ... 4153: putname(name); 4154: return error; 4155: }
linux-6.6.9/fs/namei.c 4100: int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, 4101: struct dentry *dentry, umode_t mode) 4102: { ... 4110: if (!dir->i_op->mkdir) 4111: return -EPERM; ... 4121: error = dir->i_op->mkdir(idmap, dir, dentry, mode); ... 4124: return error; 4125: }
アンケートはTwinsから回答してください。
なお、皆さんの評価が成績に影響することは一切ありません。 また、評価結果を教育の改善以外の目的に利用することはありませんし、 評価結果を公開する場合には個人を特定できるような情報は含めません。
2月26日までに回答して下さい。
void f(int arg1, int arg2) { 省略; }これを実現するために、どのような Work Queue のハンドラと初期化コードを書け ばよいか。以下の空欄を埋めなさい。
static struct /*空欄(a)*/ wq1; void work_queue_handler(struct work_struct *work) { /* Work Queue ハンドラ */ int arg1, arg2; arg1 = 省略; /* f() の引数 */ arg2 = 省略; /* f() の引数 */ /*空欄(b)*/ } 初期化 { /*空欄(c)*/(&wq1, /*空欄(d)*/); }
irqreturn_t irq_handler(int irq, void *dev) { /*空欄(e)*/(/*空欄(f)*/); return IRQ_HANDLED; }
このページで説明されている関数のうち、次のものを1つずつ上げなさい。
2024/02/07 18:00訂正済み。空欄(i)が2つあったので、1つを空欄(j)にしました。
int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, const char *oldname) { int error; ... if (!/*空欄(g)*/->i_op->/*空欄(h)*/) return -EPERM; ... error = /*空欄(g)*/->i_op->/*空欄(h)*/(idmap, /*空欄(i)*/, /*空欄(j)*/, /*省略*/); ... return error; }訂正前の誤りを含む行。
error = /*空欄(g)*/->i_op->/*空欄(h)*/(idmap, /*空欄(j)*/, /*空欄(i)*/, /*省略*/);