📄 inode.c
字号:
/* * The dentry->d_count stuff confuses d_delete() enough to * not kill the inode from under us while it is locked. This * wouldn't be needed, except the dentry semaphore is really * in the inode, not in the dentry.. */ fist_print_dentry("wrapfs_rmdir-hidden_dentry1", hidden_dentry); hidden_dentry->d_count++; double_lock(hidden_dir_dentry, hidden_dentry); if (!check_parent(hidden_dir_dentry, hidden_dentry)) goto out_lock; /* avoid destroying the hidden inode if the file is in use */ dget(hidden_dentry); err = vfs_rmdir(hidden_dir_dentry->d_inode, hidden_dentry); dput(hidden_dentry); if (!err) d_delete(hidden_dentry); out_lock: fist_copy_attr_times(dir, hidden_dir_dentry->d_inode); /* copy the nlink count for our dentry and our parent's dentry */ dir->i_nlink = hidden_dir_dentry->d_inode->i_nlink; double_unlock(hidden_dentry, hidden_dir_dentry); fist_print_dentry("wrapfs_rmdir-dentry", dentry); fist_print_inode("wrapfs_rmdir-inode", dentry->d_inode); /* * call d_drop so the system "forgets" about us */ if (!err) d_drop(dentry); dput(dentry); print_exit_status(err); return err;}STATIC intwrapfs_mknod(inode_t *dir, dentry_t *dentry, int mode, int dev){ int err; dentry_t *hidden_dentry = wrapfs_hidden_dentry(dentry); dentry_t *hidden_dir_dentry; print_entry_location(); fist_checkinode(dir, "wrapfs_mknod-dir"); hidden_dir_dentry = lock_parent(hidden_dentry); err = -ENOENT; if (!check_parent(hidden_dir_dentry, hidden_dentry)) goto out_lock; if (!hidden_dir_dentry->d_inode->i_op || !hidden_dir_dentry->d_inode->i_op->mknod) { err = -EPERM; goto out_lock; } DQUOT_INIT(hidden_dir_dentry->d_inode); err = hidden_dir_dentry->d_inode->i_op->mknod(hidden_dir_dentry->d_inode, hidden_dentry, mode, dev); if (err || !hidden_dentry->d_inode) goto out_lock; err = wrapfs_interpose(hidden_dentry, dentry, dir->i_sb, 0); if (err) goto out_lock; fist_copy_attr_timesizes(dir, hidden_dir_dentry->d_inode); out_lock: unlock_dir(hidden_dir_dentry); if (!dentry->d_inode) d_drop(dentry); out: fist_checkinode(dir, "post wrapfs_mknod-dir"); print_exit_status(err); return err;}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,6)/* this is for kernels before 2.2.6 */STATIC intwrapfs_rename(inode_t *old_dir, dentry_t *old_dentry, inode_t *new_dir, dentry_t *new_dentry){ int err = -EPERM; dentry_t *hidden_old_dentry = wrapfs_hidden_dentry(old_dentry); dentry_t *hidden_new_dentry = wrapfs_hidden_dentry(new_dentry); dentry_t *hidden_old_dir_dentry; dentry_t *hidden_new_dir_dentry; int (*rename_fxn) (inode_t *, dentry_t *, inode_t *, dentry_t *); print_entry_location(); hidden_old_dir_dentry = get_parent(hidden_old_dentry); hidden_new_dir_dentry = get_parent(hidden_new_dentry); dget(hidden_old_dentry); dget(hidden_new_dentry); double_lock(hidden_old_dir_dentry, hidden_new_dir_dentry); fist_checkinode(old_dir, "wrapfs_rename-old_dir"); fist_checkinode(new_dir, "wrapfs_rename-new_dir"); if (!hidden_old_dir_dentry->d_inode->i_op || !(rename_fxn = hidden_old_dir_dentry->d_inode->i_op->rename)) { err = -EPERM; goto out_lock; } err = rename_fxn(hidden_old_dir_dentry->d_inode, hidden_old_dentry, hidden_new_dir_dentry->d_inode, hidden_new_dentry); if (err) goto out_lock; // ASSERT(new_dentry->d_inode == NULL); // new_dentry->d_inode = old_dentry->d_inode; // err = wrapfs_interpose(hidden_new_dentry, new_dentry, new_dir->i_sb, 0); d_move(old_dentry, new_dentry); fist_copy_attr_all(new_dir, hidden_new_dir_dentry->d_inode); if (new_dir != old_dir) fist_copy_attr_times(old_dir, hidden_old_dir_dentry->d_inode); out_lock: double_unlock(hidden_old_dir_dentry, hidden_new_dir_dentry); out: dput(hidden_new_dentry); dput(hidden_old_dentry); fist_checkinode(new_dir, "post wrapfs_mknod-new_dir"); print_exit_status(err); return err;}#else /* not LINUX_VERSION_CODE < KERNEL_VERSION(2,2,6) *//* this is for 2.2.6 kernels and later (big rename changes) */STATIC intwrapfs_rename(inode_t *old_dir, dentry_t *old_dentry, inode_t *new_dir, dentry_t *new_dentry){ int err = -EPERM; dentry_t *hidden_old_dentry = wrapfs_hidden_dentry(old_dentry); dentry_t *hidden_new_dentry = wrapfs_hidden_dentry(new_dentry); dentry_t *hidden_old_dir_dentry; dentry_t *hidden_new_dir_dentry; int (*rename_fxn) (inode_t *, dentry_t *, inode_t *, dentry_t *); print_entry_location(); fist_checkinode(old_dir, "wrapfs_rename-old_dir"); fist_checkinode(new_dir, "wrapfs_rename-new_dir"); dget(hidden_old_dentry); dget(hidden_new_dentry); hidden_old_dir_dentry = get_parent(hidden_old_dentry); hidden_new_dir_dentry = get_parent(hidden_new_dentry); double_lock(hidden_old_dir_dentry, hidden_new_dir_dentry); err = -ENOENT; if (check_parent(hidden_old_dir_dentry, hidden_old_dentry) && check_parent(hidden_new_dir_dentry, hidden_new_dentry)) err = vfs_rename(hidden_old_dir_dentry->d_inode, hidden_old_dentry, hidden_new_dir_dentry->d_inode, hidden_new_dentry); if (err) goto out_lock; fist_copy_attr_all(new_dir, hidden_new_dir_dentry->d_inode); if (new_dir != old_dir) fist_copy_attr_all(old_dir, hidden_old_dir_dentry->d_inode); out_lock: double_unlock(hidden_old_dir_dentry, hidden_new_dir_dentry); dput(hidden_new_dentry); dput(hidden_old_dentry); fist_checkinode(new_dir, "post wrapfs_mknod-new_dir"); print_exit_status(err); return err;}#endif /* not LINUX_VERSION_CODE < KERNEL_VERSION(2,2,6) */STATIC intwrapfs_readlink(dentry_t *dentry, char *buf, int bufsiz){ int err; dentry_t *hidden_dentry = wrapfs_hidden_dentry(dentry);#ifdef FIST_FILTER_NAME char *decoded_name, *hidden_buf; mm_segment_t old_fs;#endif /* FIST_FILTER_NAME */ print_entry_location(); fist_print_dentry("wrapfs_readlink IN", dentry); if (!hidden_dentry->d_inode->i_op || !hidden_dentry->d_inode->i_op->readlink) { err = -EINVAL; goto out; }#ifndef FIST_FILTER_NAME err = hidden_dentry->d_inode->i_op->readlink(hidden_dentry, buf, bufsiz); if (err > 0) fist_copy_attr_atime(dentry->d_inode, hidden_dentry->d_inode);#else /* FIST_FILTER_NAME */ hidden_buf = kmalloc(bufsiz, GFP_KERNEL); if (hidden_buf == NULL) { printk("Out of memory.\n"); err = -ENOMEM; goto out; } old_fs = get_fs(); set_fs(KERNEL_DS); err = hidden_dentry->d_inode->i_op->readlink(hidden_dentry, hidden_buf, bufsiz); set_fs(old_fs); if (err >= 0) { fist_dprint(7, "READLINK: link \"%s\", length %d\n", hidden_buf, err); err = wrapfs_decode_filename(hidden_buf, err, &decoded_name, DO_DOTS, dentry->d_inode, dentry->d_sb); if (err > 0) { if (copy_to_user(buf, decoded_name, err)) err = -EFAULT; kfree_s(decoded_name, err); } fist_copy_attr_atime(dentry->d_inode, hidden_dentry->d_inode); } kfree_s(hidden_buf, bufsiz);#endif /* FIST_FILTER_NAME */ out: print_exit_status(err); return err;}/* inode is from wrapfs, dir could be anything */STATIC dentry_t *wrapfs_follow_link(dentry_t *dentry, dentry_t *base, unsigned int follow){ char *buf; int len = PAGE_SIZE, err; dentry_t *ret_dentry = dentry; dentry_t *hidden_dentry = wrapfs_hidden_dentry(dentry); mm_segment_t old_fs; print_entry_location(); // fist_print_dentry("wrapfs_follow_link dentry IN", dentry); // fist_print_dentry("wrapfs_follow_link base IN", base); if (!hidden_dentry->d_inode->i_op || !hidden_dentry->d_inode->i_op->readlink || !hidden_dentry->d_inode->i_op->follow_link) { /* * do_follow_link will do a dput() on the dentry passed to us * and if that is the same as ret_dentry, and we want it kept, * then we must increment the dentry's refcount to avoid having * it deallocate/destroyed. */ dget(ret_dentry); /* * Looking at do_follow_link, if we implement follow_link, then * we have to dput(base). Normally that's done by lookup_dentry * but here we don't run that code. */ dput(base); goto out; } buf = kmalloc(len, GFP_KERNEL); if (!buf) { ret_dentry = ERR_PTR(-ENOMEM); dput(base); // for the same reason as above goto out; } /* read the hidden symlink, and then we will follow it */ old_fs = get_fs(); set_fs(KERNEL_DS); err = dentry->d_inode->i_op->readlink(dentry, buf, len); set_fs(old_fs); if (err < 0) { ret_dentry = ERR_PTR(err); dput(base); // for the same reason as above goto out_free; } fist_copy_attr_atime(dentry->d_inode, hidden_dentry->d_inode); buf[err] = 0; // terminate the buffer for lookup_dentry's sake /* * We do not dget(base) b/c the way we were called here, * the base (passed to us) was already dget'ed. */ ret_dentry = lookup_dentry(buf, base, follow); // fist_print_dentry("wrapfs_follow_link base OUT", base); out_free: kfree_s(buf, len); out: print_exit_location(); return ret_dentry;}#if 0STATIC voidfist_page_mkclean(page_t *page){ unsigned long address; pmd_t *pmd; pgd_t *pgd; pte_t *ppte; ASSERT(page != NULL); ASSERT(page->inode != NULL); ASSERT(page->inode->i_mmap != NULL); ASSERT(page->inode->i_mmap->vm_mm != NULL); ASSERT(page->inode->i_mmap->vm_mm->pgd != NULL); address = page->offset; pgd = page->inode->i_mmap->vm_mm->pgd; pmd = pmd_offset(pgd, address); ppte = pte_offset(pmd, address); set_pte(ppte, pte_mkclean(*ppte)); ASSERT(!pte_dirty(*ppte));}STATIC voidfist_page_assertclean(page_t *page){ unsigned long address; pmd_t *pmd; pgd_t *pgd; pte_t *ppte; ASSERT(page != NULL); ASSERT(page->inode != NULL); ASSERT(page->inode->i_mmap != NULL); ASSERT(page->inode->i_mmap->vm_mm != NULL); ASSERT(page->inode->i_mmap->vm_mm->pgd != NULL); address = page->offset; pgd = page->inode->i_mmap->vm_mm->pgd; pmd = pmd_offset(pgd, address); ppte = pte_offset(pmd, address); // set_pte(ppte, pte_mkclean(*ppte)); ASSERT(!pte_dirty(*ppte));}#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)static inlinestruct page *__read_cache_page(struct inode *inode, unsigned long offset, int (*filler)(void *,struct page*), void *data){ struct page **hash = page_hash(inode, offset); struct page *page; unsigned long cached_page = 0; int err; offset &= PAGE_CACHE_MASK;repeat: page = __find_page(inode, offset, *hash); if (!page) { if (!cached_page) { cached_page = page_cache_alloc(); if (!cached_page) return ERR_PTR(-ENOMEM); goto repeat; } page = page_cache_entry(cached_page); cached_page = 0; add_to_page_cache(page, inode, offset, hash); set_bit(PG_locked, &page->flags); err = filler(data, page); if (err < 0) { page_cache_release(page); page = ERR_PTR(err); } } if (cached_page) page_cache_free(cached_page); return page;}/* * Read into the page cache. If a page already exists, * and Page_Uptodate() is not set, try to fill the page. */struct page *read_cache_page(struct inode *inode, unsigned long offset, int (*filler)(void *,struct page*),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -