📄 attach.c
字号:
/* * Copyright (c) 1997-2003 Erez Zadok * Copyright (c) 2001-2003 Stony Brook University * Copyright (c) 1997-2000 Columbia University * * For specific licensing information, see the COPYING file distributed with * this package, or get one from ftp://ftp.filesystems.org/pub/fist/COPYING. * * This Copyright notice must be kept intact and distributed with all * fistgen sources INCLUDING sources generated by fistgen. *//* * $Id: attach.c,v 1.11 2002/12/27 20:19:03 ezk Exp $ */#ifdef HAVE_CONFIG_H# include <config.h>#endif /* HAVE_CONFIG_H */#ifdef FISTGEN# include "fist_wrapfs.h"#endif /* FISTGEN */#include "fist.h"#include "wrapfs.h"/**************************************************************************** *** ATTACH/DETACH UTILITY AND LIST FUNCTIONS *** ****************************************************************************//* delete an entry if it exists *//* return true if deleted, false if not deleted */static __inline__ int del_attached_ent(super_block_t *sb, const char *name, unsigned short namelen){ attached_entry_t *ent; struct list_head *p, *t; write_lock(&(stopd(sb)->attachlock)); list_for_each_safe(p, t, &(stopd(sb)->attached)) { ent = list_entry(p, attached_entry_t, list); if (ent->e_dentry->d_name.len == namelen && strncmp(ent->e_dentry->d_name.name, name, namelen) == 0) { /* found entry: first unlink it from list, then dput, kfree*/ list_del(p); fist_print_dentry("DAEd", ent->e_dentry); d_drop(ent->e_dentry); //CPW: FIXME: d_drop correct? fist_print_dentry("DAEp", ent->e_dentry); dput(ent->e_dentry); kfree(ent); return 1; } } write_unlock(&(stopd(sb)->attachlock)); return 0;}/* add a new entry to attached list, not checking for dups */static __inline__ void add_attached(super_block_t *sb, struct dentry *d){ attached_entry_t *ent = NULL; ASSERT(d); write_lock(&(stopd(sb)->attachlock)); /* allocate and fill in entry */ ent = kmalloc(sizeof(attached_entry_t), GFP_KERNEL); ASSERT(ent); ent->e_dentry = dget(d); /* add to list */ list_add_tail(&(ent->list), &(stopd(sb)->attached)); write_unlock(&(stopd(sb)->attachlock));}/* * Attach (stack) a node named 'from', pointing to 'to' (hidden), * in the root of the mounted file system. */intdo_attach(inode_t *inode, file_t *file, const char *from, const char *to){ int err = -EINVAL; dentry_t *hidden_dentry = ERR_PTR(-EINVAL); dentry_t *this_dentry; struct nameidata from_nd, to_nd; super_block_t *this_sb; print_entry_location(); printk("XXX: ATTACH %s -> %s\n", from, to); // XXX: major issue: what inode number do we use? // hidden inums could be duplicate... /* get hidden (to) dentry */ if (path_init(to, LOOKUP_FOLLOW, &to_nd)) err = path_walk(to, &to_nd); if (err) { printk("%s: error accessing hidden directory '%s'\n", __FUNCTION__, to); goto out; } // hidden_dentry->d_inode must exist hidden_dentry = to_nd.dentry; if (IS_ERR(hidden_dentry)) { printk(KERN_WARNING "%s: lookup_dentry failed (err = %ld)\n", __FUNCTION__, PTR_ERR(hidden_dentry)); err = -ENOENT; goto out; /* CPW: FIXME: This probably needs to free resources */ } if (!hidden_dentry->d_inode) { printk(KERN_WARNING "%s: no directory to interpose on\n", __FUNCTION__); err = -ENOENT; goto out; /* CPW: FIXME: This probably needs to free resources */ } if (!S_ISDIR(hidden_dentry->d_inode->i_mode)) { printk(KERN_WARNING "%s: can only interpose on top of directories\n", __FUNCTION__); err = -ENOTDIR; goto out; /* CPW: FIXME: This probably needs to free resources */ } if (vfs_permission(hidden_dentry->d_inode, MAY_READ | MAY_EXEC)) { printk(KERN_WARNING "%s: can not interpose on directories without rx permission\n", __FUNCTION__); err = -EPERM; goto out; } if (vfs_permission(hidden_dentry->d_inode, MAY_WRITE | MAY_EXEC)) { printk(KERN_WARNING "%s: can not interpose without wx permission on mountpoint\n", __FUNCTION__); err = -EPERM; goto out; } this_sb = inode->i_sb; fist_print_dentry("TOd", hidden_dentry); /* XXX: mkdir the "from" dir??? */ /* XXX: do we need to dget() file->f_dentry (parent dir)? */ this_dentry = lookup_one_len(from, file->f_dentry, strlen(from)); if (IS_ERR(this_dentry)) { err = PTR_ERR(this_dentry); printk("lookup_one_len %*s in %*s failed", strlen(from), from, file->f_dentry->d_name.len, file->f_dentry->d_name.name); goto out; } /* must initialize dentry operations */ this_dentry->d_op = &wrapfs_dops; fist_print_dentry("FROMd", this_dentry); // prepare hidden_dentry and then interpose both ASSERT(dtopd(this_dentry) == NULL); dtopd(this_dentry) = (struct wrapfs_dentry_info *) kmalloc(sizeof(struct wrapfs_dentry_info), GFP_KERNEL); if (!dtopd(this_dentry)) { err = -ENOMEM; goto outdput; } dtohd(this_dentry) = hidden_dentry; err = wrapfs_interpose(hidden_dentry, this_dentry, this_sb, 0); if (err) goto outfree; fist_print_dentry("DAd", this_dentry); fist_print_dentry("DAp", this_dentry->d_parent); fist_print_inode("DAi", this_dentry->d_inode); add_attached(inode->i_sb, this_dentry); /* increment the reference count for our superblock */ mntget(file->f_vfsmnt); // XXX: how do we link root dentry to attached ones? d_rehash(this_dentry); goto outdput; outfree: d_drop(this_dentry); kfree(dtopd(this_dentry)); dtopd(this_dentry) = NULL; outdput: dput(this_dentry); out: print_exit_status(err); return err;}/* * Detach (unstack) a node named 'from' in the root of the mounted file system. */intdo_detach(inode_t *inode, file_t *file, const char *from){ attached_entry_t *ent; struct list_head *p; int namelen; int err = 0; print_entry_location(); printk("XXX: DETACH %s\n", from); namelen = strlen(from); if(!capable(CAP_SYS_ADMIN)) { read_lock(&(stopd(inode->i_sb)->attachlock)); list_for_each(p, &(stopd(inode->i_sb)->attached)) { ent = list_entry(p, attached_entry_t, list); ASSERT(ent->e_dentry); if (ent->e_dentry->d_name.len == namelen && strncmp(ent->e_dentry->d_name.name, from, namelen) == 0) { if (vfs_permission(ent->e_dentry->d_inode, MAY_WRITE|MAY_EXEC)) { err = -EPERM; read_unlock(&(stopd(inode->i_sb)->attachlock)); goto out; } break; } } read_unlock(&(stopd(inode->i_sb)->attachlock)); } if (!del_attached_ent(file->f_dentry->d_inode->i_sb, from, namelen)) { err = -ENOENT; goto out; } /* decrement the reference count for our superblock */ mntput(file->f_vfsmnt); out: print_exit_status(err); return err;}/**************************************************************************** *** MOUNT-TIME OPS *** ****************************************************************************/super_block_t *wrapfs_read_super(super_block_t *sb, void *raw_data, int silent){ super_block_t *ret_sb = NULL; inode_t *inode; print_entry_location(); /* XXX: not a valid test any longer, b/c we're not forcing dir=XXX option */ if (!raw_data) { printk(KERN_WARNING "wrapfs_read_super_attach: missing data argument\n"); goto out; } /* initialize private data */ stopd(sb) = kmalloc(sizeof(struct wrapfs_sb_info), GFP_KERNEL); if (!stopd(sb)) { printk(KERN_WARNING "%s (attach): no memory\n", __FUNCTION__); goto out; } stopd(sb)->hidden_mnt = NULL; stopd(sb)->wsi_sb = NULL; stopd(sb)->attachlock = RW_LOCK_UNLOCKED; INIT_LIST_HEAD(&(stopd(sb)->attached)); /* hidden_root = */ wrapfs_parse_options(sb, raw_data); /* * XXX: problem: we could attach multiple directories from file systems * with differnet maxbytes. Will it work to set it to MAX_NON_LFS or * "infinity"? */ sb->s_maxbytes = MAX_NON_LFS; sb->s_op = &wrapfs_sops; /* * we can't use d_alloc_root if we want to use * our own interpose function unchanged, * so we simply replicate *most* of the code in d_alloc_root here */ /* * XXX: for the "attach" version of this function, we might be able to * use d_alloc_root similarly to how proc_read_super() uses it. */ sb->s_root = d_alloc(NULL, &(const struct qstr) { "/", 1, 0 }); if (IS_ERR(sb->s_root)) { printk(KERN_WARNING "wrapfs_read_super_attach: d_alloc failed\n"); goto out; } /* XXX: do we need an "attach" version of wrapfs_dops? */ sb->s_root->d_op = &wrapfs_attach_dops; sb->s_root->d_sb = sb; sb->s_root->d_parent = sb->s_root; /* link the upper and lower dentries */ dtopd(sb->s_root) = NULL; /* XXX: copied from wrapfs_interpose (code needs to be split/reorganized) */ inode = iget(sb, 1); /* XXX: use get_empty_inode() later */ if (!inode) { printk(KERN_WARNING "wrapfs_read_super_attach: iget failed\n"); goto out_dput2; } inode->i_op = &wrapfs_dir_attach_iops; /* XXX: need "attach" version of ops? */ inode->i_fop = &wrapfs_dir_attach_fops; /* XXX: need "attach" version of ops? */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -