📄 dir.c
字号:
return error; } presto_unlock(dir); if ( presto_get_permit(dir) < 0 ) { EXIT; presto_fulllock(dir); return -EROFS; } memset(&info, 0, sizeof(info)); if (!ISLENTO(presto_c2m(cache))) info.flags = LENTO_FL_KML; info.flags |= LENTO_FL_IGNORE_TIME; presto_relock_sem(dir); parent = dentry->d_parent; error = presto_do_mkdir(fset, parent, dentry, mode, &info); presto_relock_other(dir); presto_put_permit(dir); return error;}static int presto_symlink(struct inode *dir, struct dentry *dentry, const char *name){ int error; struct presto_cache *cache; struct presto_file_set *fset; struct dentry *parent = dentry->d_parent; struct lento_vfs_context info; ENTRY; error = presto_prep(dentry->d_parent, &cache, &fset); if ( error ) { EXIT; return error; } presto_unlock(dir); if ( presto_get_permit(dir) < 0 ) { EXIT; presto_fulllock(dir); return -EROFS; } presto_relock_sem(dir); parent = dentry->d_parent; memset(&info, 0, sizeof(info)); if (!ISLENTO(presto_c2m(cache))) info.flags = LENTO_FL_KML; info.flags |= LENTO_FL_IGNORE_TIME; error = presto_do_symlink(fset, parent, dentry, name, &info); presto_relock_other(dir); presto_put_permit(dir); return error;}int presto_unlink(struct inode *dir, struct dentry *dentry){ int error; struct presto_cache *cache; struct presto_file_set *fset; struct dentry *parent = dentry->d_parent; struct lento_vfs_context info; ENTRY; error = presto_prep(dentry->d_parent, &cache, &fset); if ( error ) { EXIT; return error; } presto_unlock(dir); if ( presto_get_permit(dir) < 0 ) { EXIT; presto_fulllock(dir); return -EROFS; } presto_relock_sem(dir); parent = dentry->d_parent; memset(&info, 0, sizeof(info)); if (!ISLENTO(presto_c2m(cache))) info.flags = LENTO_FL_KML; info.flags |= LENTO_FL_IGNORE_TIME; error = presto_do_unlink(fset, parent, dentry, &info); presto_relock_other(dir); presto_put_permit(dir); return error;}static int presto_rmdir(struct inode *dir, struct dentry *dentry){ int error; struct presto_cache *cache; struct presto_file_set *fset; struct dentry *parent = dentry->d_parent; struct lento_vfs_context info; ENTRY; CDEBUG(D_FILE, "prepping presto\n"); error = presto_prep(dentry->d_parent, &cache, &fset); if ( error ) { EXIT; return error; } CDEBUG(D_FILE, "unlocking\n"); /* We need to dget() before the dput in double_unlock, to ensure we * still have dentry references. double_lock doesn't do dget for us. */ unlock_kernel(); if (d_unhashed(dentry)) d_rehash(dentry); double_up(&dir->i_zombie, &dentry->d_inode->i_zombie); double_up(&dir->i_sem, &dentry->d_inode->i_sem); CDEBUG(D_FILE, "getting permit\n"); if ( presto_get_permit(parent->d_inode) < 0 ) { EXIT; double_down(&dir->i_sem, &dentry->d_inode->i_sem); double_down(&dir->i_zombie, &dentry->d_inode->i_zombie); lock_kernel(); return -EROFS; } CDEBUG(D_FILE, "locking\n"); double_down(&dir->i_sem, &dentry->d_inode->i_sem); parent = dentry->d_parent; memset(&info, 0, sizeof(info)); if (!ISLENTO(presto_c2m(cache))) info.flags = LENTO_FL_KML; info.flags |= LENTO_FL_IGNORE_TIME; error = presto_do_rmdir(fset, parent, dentry, &info); presto_put_permit(parent->d_inode); lock_kernel(); EXIT; return error;}static int presto_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev){ int error; struct presto_cache *cache; struct presto_file_set *fset; struct dentry *parent = dentry->d_parent; struct lento_vfs_context info; ENTRY; error = presto_prep(dentry->d_parent, &cache, &fset); if ( error ) { EXIT; return error; } presto_unlock(dir); if ( presto_get_permit(dir) < 0 ) { EXIT; presto_fulllock(dir); return -EROFS; } presto_relock_sem(dir); parent = dentry->d_parent; memset(&info, 0, sizeof(info)); if (!ISLENTO(presto_c2m(cache))) info.flags = LENTO_FL_KML; info.flags |= LENTO_FL_IGNORE_TIME; error = presto_do_mknod(fset, parent, dentry, mode, rdev, &info); presto_relock_other(dir); presto_put_permit(dir); EXIT; return error;}inline void presto_triple_unlock(struct inode *old_dir, struct inode *new_dir, struct dentry *old_dentry, struct dentry *new_dentry, int triple){ /* rename_dir case */ if (S_ISDIR(old_dentry->d_inode->i_mode)) { if (triple) { triple_up(&old_dir->i_zombie, &new_dir->i_zombie, &new_dentry->d_inode->i_zombie); } else { double_up(&old_dir->i_zombie, &new_dir->i_zombie); } up(&old_dir->i_sb->s_vfs_rename_sem); } else /* this case is rename_other */ double_up(&old_dir->i_zombie, &new_dir->i_zombie); /* done by do_rename */ unlock_kernel(); double_up(&old_dir->i_sem, &new_dir->i_sem);}inline void presto_triple_fulllock(struct inode *old_dir, struct inode *new_dir, struct dentry *old_dentry, struct dentry *new_dentry, int triple){ /* done by do_rename */ double_down(&old_dir->i_sem, &new_dir->i_sem); lock_kernel(); /* rename_dir case */ if (S_ISDIR(old_dentry->d_inode->i_mode)) { down(&old_dir->i_sb->s_vfs_rename_sem); if (triple) { triple_down(&old_dir->i_zombie, &new_dir->i_zombie, &new_dentry->d_inode->i_zombie); } else { double_down(&old_dir->i_zombie, &new_dir->i_zombie); } } else /* this case is rename_other */ double_down(&old_dir->i_zombie, &new_dir->i_zombie);}inline void presto_triple_relock_sem(struct inode *old_dir, struct inode *new_dir, struct dentry *old_dentry, struct dentry *new_dentry, int triple){ /* done by do_rename */ double_down(&old_dir->i_sem, &new_dir->i_sem); lock_kernel();}inline void presto_triple_relock_other(struct inode *old_dir, struct inode *new_dir, struct dentry *old_dentry, struct dentry *new_dentry, int triple){ /* rename_dir case */ if (S_ISDIR(old_dentry->d_inode->i_mode)) { down(&old_dir->i_sb->s_vfs_rename_sem); if (triple) { triple_down(&old_dir->i_zombie, &new_dir->i_zombie, &new_dentry->d_inode->i_zombie); } else { double_down(&old_dir->i_zombie, &new_dir->i_zombie); } } else /* this case is rename_other */ double_down(&old_dir->i_zombie, &new_dir->i_zombie);}// XXX this can be optimized: renamtes across filesets only require // multiple KML records, but can locally be executed normally. int presto_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry){ int error; struct presto_cache *cache, *new_cache; struct presto_file_set *fset, *new_fset; struct lento_vfs_context info; struct dentry *old_parent = old_dentry->d_parent; struct dentry *new_parent = new_dentry->d_parent; int triple; ENTRY; error = presto_prep(old_dentry, &cache, &fset); if ( error ) { EXIT; return error; } error = presto_prep(new_parent, &new_cache, &new_fset); if ( error ) { EXIT; return error; } if ( fset != new_fset ) { EXIT; return -EXDEV; } /* We need to do dget before the dput in double_unlock, to ensure we * still have dentry references. double_lock doesn't do dget for us. */ triple = (S_ISDIR(old_dentry->d_inode->i_mode) && new_dentry->d_inode)? 1:0; presto_triple_unlock(old_dir, new_dir, old_dentry, new_dentry, triple); if ( presto_get_permit(old_dir) < 0 ) { EXIT; presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); return -EROFS; } if ( presto_get_permit(new_dir) < 0 ) { EXIT; presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); return -EROFS; } presto_triple_relock_sem(old_dir, new_dir, old_dentry, new_dentry, triple); memset(&info, 0, sizeof(info)); if (!ISLENTO(presto_c2m(cache))) info.flags = LENTO_FL_KML; info.flags |= LENTO_FL_IGNORE_TIME; error = presto_do_rename(fset, old_parent, old_dentry, new_parent, new_dentry, &info); presto_triple_relock_other(old_dir, new_dir, old_dentry, new_dentry, triple); presto_put_permit(new_dir); presto_put_permit(old_dir); return error;}/* basically this allows the ilookup processes access to all files for * reading, while not making ilookup totally insecure. This could all * go away if we could set the CAP_DAC_READ_SEARCH capability for the client. *//* If posix acls are available, the underlying cache fs will export the * appropriate permission function. Thus we do not worry here about ACLs * or EAs. -SHP */int presto_permission(struct inode *inode, int mask){ unsigned short mode = inode->i_mode; struct presto_cache *cache; int rc; ENTRY; if ( presto_can_ilookup() && !(mask & S_IWOTH)) { CDEBUG(D_CACHE, "ilookup on %ld OK\n", inode->i_ino); EXIT; return 0; } cache = presto_get_cache(inode); if ( cache ) { /* we only override the file/dir permission operations */ struct inode_operations *fiops = filter_c2cfiops(cache->cache_filter); struct inode_operations *diops = filter_c2cdiops(cache->cache_filter); if ( S_ISREG(mode) && fiops && fiops->permission ) { EXIT; return fiops->permission(inode, mask); } if ( S_ISDIR(mode) && diops && diops->permission ) { EXIT; return diops->permission(inode, mask); } } /* The cache filesystem doesn't have its own permission function, * but we don't want to duplicate the VFS code here. In order * to avoid looping from permission calling this function again, * we temporarily override the permission operation while we call * the VFS permission function. */ inode->i_op->permission = NULL; rc = permission(inode, mask); inode->i_op->permission = &presto_permission; EXIT; return rc;}static int presto_dir_open(struct inode *inode, struct file *file){ int rc = 0; struct dentry *de = file->f_dentry; struct file_operations *fops; struct presto_cache *cache; struct presto_file_set *fset; int minor; int error; ENTRY; error = presto_prep(file->f_dentry, &cache, &fset); if ( error ) { EXIT; make_bad_inode(inode); return error; } minor = presto_c2m(cache); CDEBUG(D_CACHE, "minor %d, DATA_OK: %d, ino: %ld\n", minor, presto_chk(de, PRESTO_DATA), inode->i_ino); if ( ISLENTO(minor) ) goto cache; if ( !presto_chk(de, PRESTO_DATA) ) { CDEBUG(D_CACHE, "doing lento_opendir\n"); rc = presto_opendir_upcall(minor, file->f_dentry, fset->fset_mtpt, SYNCHRONOUS); } if ( rc ) { printk("presto_dir_open: DATA_OK: %d, ino: %ld, error %d\n", presto_chk(de, PRESTO_DATA), inode->i_ino, rc); return rc ; } cache: fops = filter_c2cdfops(cache->cache_filter); if ( fops->open ) { rc = fops->open(inode, file); } presto_set(de, PRESTO_DATA | PRESTO_ATTR); CDEBUG(D_CACHE, "returns %d, data %d, attr %d\n", rc, presto_chk(de, PRESTO_DATA), presto_chk(de, PRESTO_ATTR)); return 0;}struct file_operations presto_dir_fops = { open: presto_dir_open};struct inode_operations presto_dir_iops = { create: presto_create, lookup: presto_lookup, link: presto_link, unlink: presto_unlink, symlink: presto_symlink, mkdir: presto_mkdir, rmdir: presto_rmdir, mknod: presto_mknod, rename: presto_rename, permission: presto_permission, setattr: presto_setattr,#ifdef CONFIG_FS_EXT_ATTR set_ext_attr: presto_set_ext_attr,#endif};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -