(內(nèi)核2.4.37)
一,、
當(dāng)我們打開一個文件的時候,,需要獲得文件的文件描述符(前面已經(jīng)說過其實就是文件數(shù)組下標(biāo)),,一般是通過函數(shù)open來完成,,這個系統(tǒng)調(diào)用在<unistd.h>頭文件中聲明定義,我們看一下源碼:
- 530 static inline long open(const char * name, int mode, int flags)
- 531 {
- 532 return sys_open(name, mode, flags);
- 533 }
Ps:對于這些參數(shù)一般我們都很熟悉,,經(jīng)常使用,,這里順便提出記憶一下:
mode:參數(shù)可選:
- 32 #define S_IRWXU 00700 文件所有者可讀可寫可執(zhí)行
- 33 #define S_IRUSR 00400 文件所有者可讀
- 34 #define S_IWUSR 00200 文件所有者可寫
- 35 #define S_IXUSR 00100 文件所有者可執(zhí)行
- 36
- 37 #define S_IRWXG 00070 文件用戶組可寫可讀可執(zhí)行
- 38 #define S_IRGRP 00040 文件用戶組可讀
- 39 #define S_IWGRP 00020 文件用戶組可寫
- 40 #define S_IXGRP 00010 文件用戶組可執(zhí)行
- 41
- 42 #define S_IRWXO 00007 其他用戶可寫可讀可執(zhí)行
- 43 #define S_IROTH 00004 其他用戶可讀
- 44 #define S_IWOTH 00002 其他用戶可寫
- 45 #define S_IXOTH 00001 其他用戶可執(zhí)行
flags:在fcntl.h中定義
- 7 #define O_RDONLY 00
- 8 #define O_WRONLY 01
- 9 #define O_RDWR 02
- 10 #define O_CREAT 0100 /* not fcntl */
- 11 #define O_EXCL 0200 /* not fcntl */
- 12 #define O_NOCTTY 0400 /* not fcntl */
- 13 #define O_TRUNC 01000 /* not fcntl */
- 14 #define O_APPEND 02000
- 15 #define O_NONBLOCK 04000
- 16 #define O_NDELAY O_NONBLOCK
- 17 #define O_SYNC 010000
- 18 #define FASYNC 020000 /* fcntl, for BSD compatibility */
- 19 #define O_DIRECT 040000 /* direct disk access hint */
- 20 #define O_LARGEFILE 0100000
- 21 #define O_DIRECTORY 0200000 /* must be a directory */
- 22 #define O_NOFOLLOW 0400000 /* don't follow links */
O_RDONLY 以只讀方式打開文件
O_WRONLY 以只寫方式打開文件
O_RDWR 以讀和寫的方式打開文件
上面三個只能選擇一個,下面的可以合理的任意組合:
O_CREAT 打開文件,,如果文件不存在則建立文件
O_EXCL 如果已經(jīng)置O_CREAT且文件存在,,則強(qiáng)制open()失敗
O_TRUNC 將文件的長度截為0
O_APPEND 強(qiáng)制write()從文件尾開始
對于終端文件,上面四個是無效,,提供了兩個新的標(biāo)志:
O_NOCTTY 停止這個終端作為控制終端
O_NONBLOCK 使open(),、read()、write()不被阻塞,。
我們可以看到,,里面實際調(diào)用的是sys_open這個系統(tǒng)調(diào)用,其實想想也很正常,,對于我的一個系統(tǒng)而言,,可以存在很多組不同的文件系統(tǒng),對于不同的文件系統(tǒng),,打開文件的方式肯定是不一樣的,,所有內(nèi)核需要根據(jù)具體的文件系統(tǒng)的類型去調(diào)用不同的函數(shù)進(jìn)行執(zhí)行。現(xiàn)在看看sys_open函數(shù)(fs/open.c中):
- 800 asmlinkage long sys_open(const char * filename, int flags, int mode)
- 801 {
- 802 char * tmp;
- 803 int fd, error;
- 804
- 805 #if BITS_PER_LONG != 32
- 806 flags |= O_LARGEFILE;
- 807 #endif
- 808 tmp = getname(filename); /* 1 */
- 809 fd = PTR_ERR(tmp);
- 810 if (!IS_ERR(tmp)) {
- 811 fd = get_unused_fd(); /* 2 */
- 812 if (fd >= 0) {
- 813 struct file *f = filp_open(tmp, flags, mode); /* 3 */
- 814 error = PTR_ERR(f);
- 815 if (IS_ERR(f))
- 816 goto out_error;
- 817 fd_install(fd, f); /* 4 */
- 818 }
- 819 out:
- 820 putname(tmp);
- 821 }
- 822 return fd;
- 823
- 824 out_error:
- 825 put_unused_fd(fd);
- 826 fd = error;
- 827 goto out;
- 828 }
主要看上面注釋表示的四大步驟/* 1 */ /* 2 */ /* 3 */ /* 4 */
/* 1 */:這步是一個輔助步驟,,將filename從用戶態(tài)拷貝到內(nèi)核態(tài)變量中,。基本步驟涉及一下幾個函數(shù):
- 125 char * getname(const char * filename)
- 126 {
- 127 char *tmp, *result;
- 128
- 129 result = ERR_PTR(-ENOMEM);
- 130 tmp = __getname(); /* 這玩意吧其實是分配內(nèi)核中空間用戶裝name */
- 131 if (tmp) {
- 132 int retval = do_getname(filename, tmp); /* 其實就是將filename拷貝到tmp中 */
- 133
- 134 result = tmp;
- 135 if (retval < 0) {
- 136 putname(tmp);
- 137 result = ERR_PTR(retval);
- 138 }
- 139 }
- 140 return result;
- 141 }
看一下__getname()函數(shù):
- 1099 #define __getname() kmem_cache_alloc(names_cachep, SLAB_KERNEL)
就是在內(nèi)核的slab空間中分配能夠容納name的空間~~~
看一下do_getname()函數(shù):
- 104 static inline int do_getname(const char *filename, char *page)
- 105 {
- 106 int retval;
- 107 unsigned long len = PATH_MAX;
- 108
- 109 if ((unsigned long) filename >= TASK_SIZE) {
- 110 if (!segment_eq(get_fs(), KERNEL_DS))
- 111 return -EFAULT;
- 112 } else if (TASK_SIZE - (unsigned long) filename < PATH_MAX)
- 113 len = TASK_SIZE - (unsigned long) filename;
- 114
- 115 retval = strncpy_from_user((char *)page, filename, len);/* 核心的一個步驟,,其實就是將filename拷貝到剛剛在內(nèi)核中分配的空間中 */
- 116 if (retval > 0) {
- 117 if (retval < len)
- 118 return 0;
- 119 return -ENAMETOOLONG;
- 120 } else if (!retval)
- 121 retval = -ENOENT;
- 122 return retval;
- 123 }
/* 2 */:這一步是需要找到一個沒有使用的文件描述符fd
看一下這個函數(shù)get_unused_fd:看這個鏈接:get_unused_fd
/* 3 */:再回到上面看/* 3 */步驟,,到現(xiàn)在為止,,我們已經(jīng)找到了一個可用的文件描述符fd了,然后我們要做的就是打開指定文件,,然后將這個fd和打開的文件關(guān)聯(lián)即可,,/* 3 */步驟就是打開我們指定的文件!
下面會涉及到名字結(jié)構(gòu)nameidata,,所以先看看這個結(jié)構(gòu)體:
- 700 struct nameidata {
- 701 struct dentry *dentry; /* 當(dāng)前目錄項對象 */
- 702 struct vfsmount *mnt; /* 已安裝的文件系統(tǒng)掛載點 */
- 703 struct qstr last; /* 路徑名稱最后一部分 */
- 704 unsigned int flags; /* 查詢標(biāo)識 */
- 705 int last_type; /* 路徑名稱最后一部分類型 */
- 706 };
看這個函數(shù)filp_open:
- 644 /*
- 645 * Note that while the flag value (low two bits) for sys_open means:
- 646 * 00 - read-only
- 647 * 01 - write-only
- 648 * 10 - read-write
- 649 * 11 - special
- 650 * it is changed into
- 651 * 00 - no permissions needed
- 652 * 01 - read-permission
- 653 * 10 - write-permission
- 654 * 11 - read-write
- 655 * for the internal routines (ie open_namei()/follow_link() etc). 00 is
- 656 * used by symlinks.
- 657 */
- 658 struct file *filp_open(const char * filename, int flags, int mode)
- 659 {
- 660 int namei_flags, error;
- 661 struct nameidata nd;
- 662
- 663 namei_flags = flags;
- 664 if ((namei_flags+1) & O_ACCMODE)
- 665 namei_flags++;
- 666 if (namei_flags & O_TRUNC)
- 667 namei_flags |= 2;
- 668 /* 根據(jù)文件名打開文件 */
- 669 error = open_namei(filename, namei_flags, mode, &nd);
- 670 if (!error) /* 下面打開這個文件,,這個函數(shù)返回的是file結(jié)構(gòu)體指針!??! */
- 671 return dentry_open(nd.dentry, nd.mnt, flags);
- 672
- 673 return ERR_PTR(error);
- 674 }
這個函數(shù)比較復(fù)雜,請看這個鏈接:open_namei
回頭再看這個函數(shù),,dentry_open:這個函數(shù)返回的file結(jié)構(gòu)體指針:
- 676 struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
- 677 {
- 678 struct file * f;
- 679 struct inode *inode;
- 680 static LIST_HEAD(kill_list);
- 681 int error;
- 682
- 683 error = -ENFILE;
- 684 f = get_empty_filp(); /* 得到一個空的file結(jié)構(gòu)體,,如果出錯或者內(nèi)存不足,返回1error */
- 685 if (!f)
- 686 goto cleanup_dentry;
- 687 f->f_flags = flags; /* 一些賦值操作 */
- 688 f->f_mode = (flags+1) & O_ACCMODE;
- 689 inode = dentry->d_inode; /* 獲得文件inode */
- 690 if (f->f_mode & FMODE_WRITE) {
- 691 error = get_write_access(inode);
- 692 if (error)
- 693 goto cleanup_file;
- 694 }
- 695 /* 一些賦值操作 */
- 696 f->f_dentry = dentry; /* 目錄項 */
- 697 f->f_vfsmnt = mnt; /* 掛載點 */
- 698 f->f_pos = 0; /* 文件相對開頭偏移 */
- 699 f->f_reada = 0; /* 預(yù)讀標(biāo)志 */
- 700 f->f_op = fops_get(inode->i_fop); /* 文件操作函數(shù) */
- 701 file_move(f, &inode->i_sb->s_files);/* 將新建的file鏈接進(jìn)入inode對應(yīng)的超級塊的file鏈表中 */
- 702
- 703 /* preallocate kiobuf for O_DIRECT */
- 704 f->f_iobuf = NULL;
- 705 f->f_iobuf_lock = 0;
- 706 if (f->f_flags & O_DIRECT) {
- 707 error = alloc_kiovec(1, &f->f_iobuf); /* 分配io buffer */
- 708 if (error)
- 709 goto cleanup_all;
- 710 }
- 711 <span style="white-space:pre"> </span> /* 下面嘗試打開文件,,保證能夠正常打開這個文件 */
- 712 if (f->f_op && f->f_op->open) {
- 713 error = f->f_op->open(inode,f);
- 714 if (error)
- 715 goto cleanup_all;
- 716 }
- 717 f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
- 718
- 719 return f; /* 返回創(chuàng)建好的file */
- 720 /* 下面都是出錯處理 */
- 721 cleanup_all:
- 722 if (f->f_iobuf)
- 723 free_kiovec(1, &f->f_iobuf);
- 724 fops_put(f->f_op);
- 725 if (f->f_mode & FMODE_WRITE)
- 726 put_write_access(inode);
- 727 file_move(f, &kill_list); /* out of the way.. */
- 728 f->f_dentry = NULL;
- 729 f->f_vfsmnt = NULL;
- 730 cleanup_file:
- 731 put_filp(f);
- 732 cleanup_dentry:
- 733 dput(dentry);
- 734 mntput(mnt);
- 735 return ERR_PTR(error);
- 736 }
- 737
看一下這個函數(shù)get_empty_filp,,得到一個空的file結(jié)構(gòu)體:
- <span style="font-size:14px;"> </span>26 /* Find an unused file structure and return a pointer to it.
- 27 * Returns NULL, if there are no more free file structures or
- 28 * we run out of memory.
- 29 *
- 30 * SMP-safe.
- 31 */
- 32 struct file * get_empty_filp(void)
- 33 {
- 34 static int old_max = 0;
- 35 struct file * f;
- 36
- 37 file_list_lock();
- 38 if (files_stat.nr_free_files > NR_RESERVED_FILES) { /* 如果允許打開的數(shù)量已經(jīng)超過系統(tǒng)允許的 */
- 39 used_one:
- 40 f = list_entry(free_list.next, struct file, f_list); /* 在free_list中刪除一個,留下了給新的file使用 */
- 41 list_del(&f->f_list);
- 42 files_stat.nr_free_files--;
- 43 new_one: /* 下面創(chuàng)建一個新的file結(jié)構(gòu)體 */
- 44 memset(f, 0, sizeof(*f));
- 45 atomic_set(&f->f_count,1);
- 46 f->f_version = ++event;
- 47 f->f_uid = current->fsuid;
- 48 f->f_gid = current->fsgid;
- 49 f->f_maxcount = INT_MAX;
- 50 list_add(&f->f_list, &anon_list);
- 51 file_list_unlock();
- 52 return f; /* 返回file */
- 53 }
- 54 /*
- 55 * Use a reserved one if we're the superuser
- 56 */
- 57 if (files_stat.nr_free_files && !current->euid)
- 58 goto used_one;
- 59 /*
- 60 * Allocate a new one if we're below the limit. 如果還可以創(chuàng)建file結(jié)構(gòu)體,,那么創(chuàng)建一個新的就OK
- 61 */
- 62 if (files_stat.nr_files < files_stat.max_files) {
- 63 file_list_unlock();
- 64 f = kmem_cache_alloc(filp_cachep, SLAB_KERNEL); /* 在slab中分配一個新的file緩存 */
- 65 file_list_lock();
- 66 if (f) {
- 67 files_stat.nr_files++; /* 數(shù)量++ */
- 68 goto new_one; /* 初始化這個新的值 */
- 69 }
- 70 /* Big problems... */
- 71 printk(KERN_WARNING "VFS: filp allocation failed\n");
- 72
- 73 } else if (files_stat.max_files > old_max) {
- 74 printk(KERN_INFO "VFS: file-max limit %d reached\n", files_stat.max_files);
- 75 old_max = files_stat.max_files;
- 76 }
- 77 file_list_unlock();
- 78 return NULL;
- 79 }
/* 4 */:最后看一下fd_install函數(shù),,這個函數(shù)比較簡單,就是將之前申請的文件描述符fd和打開的文件file結(jié)構(gòu)體關(guān)聯(lián)起來:
- <span style="font-size:14px;"> </span>74 /*
- 75 * Install a file pointer in the fd array.
- 76 *
- 77 * The VFS is full of places where we drop the files lock between
- 78 * setting the open_fds bitmap and installing the file in the file
- 79 * array. At any such point, we are vulnerable to a dup2() race
- 80 * installing a file in the array before us. We need to detect this and
- 81 * fput() the struct file we are about to overwrite in this case.
- 82 *
- 83 * It should never happen - if we allow dup2() do it, _really_ bad things
- 84 * will follow.
- 85 */
- 86
- 87 void fd_install(unsigned int fd, struct file * file)
- 88 {
- 89 struct files_struct *files = current->files; /* 獲得當(dāng)前進(jìn)程文件打開表 */
- 90
- 91 write_lock(&files->file_lock);
- 92 if (files->fd[fd]) /* 如果這個fd下已經(jīng)存在文件了,,那么error,! */
- 93 BUG();
- 94 files->fd[fd] = file;/* 關(guān)聯(lián)這個fd和新打開的文件 */
- 95 write_unlock(&files->file_lock);
- 96 }
至此,文件open操作完成了~~~
|