inode.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 837 行 · 第 1/2 页
C
837 行
/* * hugetlbpage-backed filesystem. Based on ramfs. * * William Irwin, 2002 * * Copyright (C) 2002 Linus Torvalds. */#include <linux/module.h>#include <linux/thread_info.h>#include <asm/current.h>#include <linux/sched.h> /* remove ASAP */#include <linux/fs.h>#include <linux/mount.h>#include <linux/file.h>#include <linux/writeback.h>#include <linux/pagemap.h>#include <linux/highmem.h>#include <linux/init.h>#include <linux/string.h>#include <linux/backing-dev.h>#include <linux/hugetlb.h>#include <linux/pagevec.h>#include <linux/quotaops.h>#include <linux/slab.h>#include <linux/dnotify.h>#include <linux/statfs.h>#include <linux/security.h>#include <asm/uaccess.h>/* some random number */#define HUGETLBFS_MAGIC 0x958458f6static struct super_operations hugetlbfs_ops;static struct address_space_operations hugetlbfs_aops;struct file_operations hugetlbfs_file_operations;static struct inode_operations hugetlbfs_dir_inode_operations;static struct inode_operations hugetlbfs_inode_operations;static struct backing_dev_info hugetlbfs_backing_dev_info = { .ra_pages = 0, /* No readahead */ .memory_backed = 1, /* Does not contribute to dirty memory */};int sysctl_hugetlb_shm_group;static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma){ struct inode *inode = file->f_dentry->d_inode; struct address_space *mapping = inode->i_mapping; loff_t len, vma_len; int ret; if ((vma->vm_flags & (VM_MAYSHARE | VM_WRITE)) == VM_WRITE) return -EINVAL; if (vma->vm_pgoff & (HPAGE_SIZE / PAGE_SIZE - 1)) return -EINVAL; if (vma->vm_start & ~HPAGE_MASK) return -EINVAL; if (vma->vm_end & ~HPAGE_MASK) return -EINVAL; if (vma->vm_end - vma->vm_start < HPAGE_SIZE) return -EINVAL; vma_len = (loff_t)(vma->vm_end - vma->vm_start); down(&inode->i_sem); file_accessed(file); vma->vm_flags |= VM_HUGETLB | VM_RESERVED; vma->vm_ops = &hugetlb_vm_ops; ret = -ENOMEM; len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT); if (!(vma->vm_flags & VM_WRITE) && len > inode->i_size) goto out; ret = hugetlb_prefault(mapping, vma); if (ret) goto out; if (inode->i_size < len) inode->i_size = len;out: up(&inode->i_sem); return ret;}/* * Called under down_write(mmap_sem), page_table_lock is not held */#ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREAunsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags);#elsestatic unsigned longhugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags){ struct mm_struct *mm = current->mm; struct vm_area_struct *vma; if (len & ~HPAGE_MASK) return -EINVAL; if (len > TASK_SIZE) return -ENOMEM; if (addr) { addr = ALIGN(addr, HPAGE_SIZE); vma = find_vma(mm, addr); if (TASK_SIZE - len >= addr && (!vma || addr + len <= vma->vm_start)) return addr; } addr = ALIGN(mm->free_area_cache, HPAGE_SIZE); for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { /* At this point: (!vma || addr < vma->vm_end). */ if (TASK_SIZE - len < addr) return -ENOMEM; if (!vma || addr + len <= vma->vm_start) return addr; addr = ALIGN(vma->vm_end, HPAGE_SIZE); }}#endif/* * Read a page. Again trivial. If it didn't already exist * in the page cache, it is zero-filled. */static int hugetlbfs_readpage(struct file *file, struct page * page){ unlock_page(page); return -EINVAL;}static int hugetlbfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to){ return -EINVAL;}static int hugetlbfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to){ return -EINVAL;}void huge_pagevec_release(struct pagevec *pvec){ int i; for (i = 0; i < pagevec_count(pvec); ++i) put_page(pvec->pages[i]); pagevec_reinit(pvec);}void truncate_huge_page(struct page *page){ clear_page_dirty(page); ClearPageUptodate(page); remove_from_page_cache(page); put_page(page);}void truncate_hugepages(struct address_space *mapping, loff_t lstart){ const pgoff_t start = lstart >> HPAGE_SHIFT; struct pagevec pvec; pgoff_t next; int i; pagevec_init(&pvec, 0); next = start; while (1) { if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { if (next == start) break; next = start; continue; } for (i = 0; i < pagevec_count(&pvec); ++i) { struct page *page = pvec.pages[i]; lock_page(page); if (page->index > next) next = page->index; ++next; truncate_huge_page(page); unlock_page(page); hugetlb_put_quota(mapping); } huge_pagevec_release(&pvec); } BUG_ON(!lstart && mapping->nrpages);}static void hugetlbfs_delete_inode(struct inode *inode){ struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(inode->i_sb); hlist_del_init(&inode->i_hash); list_del_init(&inode->i_list); inode->i_state |= I_FREEING; inodes_stat.nr_inodes--; spin_unlock(&inode_lock); if (inode->i_data.nrpages) truncate_hugepages(&inode->i_data, 0); security_inode_delete(inode); if (sbinfo->free_inodes >= 0) { spin_lock(&sbinfo->stat_lock); sbinfo->free_inodes++; spin_unlock(&sbinfo->stat_lock); } clear_inode(inode); destroy_inode(inode);}static void hugetlbfs_forget_inode(struct inode *inode){ struct super_block *super_block = inode->i_sb; struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(super_block); if (hlist_unhashed(&inode->i_hash)) goto out_truncate; if (!(inode->i_state & (I_DIRTY|I_LOCK))) { list_del(&inode->i_list); list_add(&inode->i_list, &inode_unused); } inodes_stat.nr_unused++; if (!super_block || (super_block->s_flags & MS_ACTIVE)) { spin_unlock(&inode_lock); return; } /* write_inode_now() ? */ inodes_stat.nr_unused--; hlist_del_init(&inode->i_hash);out_truncate: list_del_init(&inode->i_list); inode->i_state |= I_FREEING; inodes_stat.nr_inodes--; spin_unlock(&inode_lock); if (inode->i_data.nrpages) truncate_hugepages(&inode->i_data, 0); if (sbinfo->free_inodes >= 0) { spin_lock(&sbinfo->stat_lock); sbinfo->free_inodes++; spin_unlock(&sbinfo->stat_lock); } clear_inode(inode); destroy_inode(inode);}static void hugetlbfs_drop_inode(struct inode *inode){ if (!inode->i_nlink) hugetlbfs_delete_inode(inode); else hugetlbfs_forget_inode(inode);}/* * h_pgoff is in HPAGE_SIZE units. * vma->vm_pgoff is in PAGE_SIZE units. */static inline voidhugetlb_vmtruncate_list(struct prio_tree_root *root, unsigned long h_pgoff){ struct vm_area_struct *vma; struct prio_tree_iter iter; vma_prio_tree_foreach(vma, &iter, root, h_pgoff, ULONG_MAX) { unsigned long h_vm_pgoff; unsigned long v_length; unsigned long v_offset; h_vm_pgoff = vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT); v_offset = (h_pgoff - h_vm_pgoff) << HPAGE_SHIFT; /* * Is this VMA fully outside the truncation point? */ if (h_vm_pgoff >= h_pgoff) v_offset = 0; v_length = vma->vm_end - vma->vm_start; zap_hugepage_range(vma, vma->vm_start + v_offset, v_length - v_offset); }}/* * Expanding truncates are not allowed. */static int hugetlb_vmtruncate(struct inode *inode, loff_t offset){ unsigned long pgoff; struct address_space *mapping = inode->i_mapping; if (offset > inode->i_size) return -EINVAL; BUG_ON(offset & ~HPAGE_MASK); pgoff = offset >> HPAGE_SHIFT; inode->i_size = offset; spin_lock(&mapping->i_mmap_lock); if (!prio_tree_empty(&mapping->i_mmap)) hugetlb_vmtruncate_list(&mapping->i_mmap, pgoff); spin_unlock(&mapping->i_mmap_lock); truncate_hugepages(mapping, offset); return 0;}static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr){ struct inode *inode = dentry->d_inode; int error; unsigned int ia_valid = attr->ia_valid; BUG_ON(!inode); error = inode_change_ok(inode, attr); if (error) goto out; if (ia_valid & ATTR_SIZE) { error = -EINVAL; if (!(attr->ia_size & ~HPAGE_MASK)) error = hugetlb_vmtruncate(inode, attr->ia_size); if (error) goto out; attr->ia_valid &= ~ATTR_SIZE; } error = inode_setattr(inode, attr);out: return error;}static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, gid_t gid, int mode, dev_t dev){ struct inode *inode; struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(sb); if (sbinfo->free_inodes >= 0) { spin_lock(&sbinfo->stat_lock); if (!sbinfo->free_inodes) { spin_unlock(&sbinfo->stat_lock); return NULL; } sbinfo->free_inodes--; spin_unlock(&sbinfo->stat_lock); } inode = new_inode(sb); if (inode) { struct hugetlbfs_inode_info *info; inode->i_mode = mode; inode->i_uid = uid; inode->i_gid = gid; inode->i_blksize = HPAGE_SIZE; inode->i_blocks = 0; inode->i_mapping->a_ops = &hugetlbfs_aops; inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; info = HUGETLBFS_I(inode); mpol_shared_policy_init(&info->policy); switch (mode & S_IFMT) { default: init_special_inode(inode, mode, dev); break; case S_IFREG: inode->i_op = &hugetlbfs_inode_operations; inode->i_fop = &hugetlbfs_file_operations; break; case S_IFDIR: inode->i_op = &hugetlbfs_dir_inode_operations; inode->i_fop = &simple_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ inode->i_nlink++; break; case S_IFLNK: inode->i_op = &page_symlink_inode_operations; break; } } return inode;}/* * File creation. Allocate an inode, and we're done.. */static int hugetlbfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev){ struct inode *inode; int error = -ENOSPC; gid_t gid;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?