📄 vfs.c
字号:
size = PRESTO_REQHIGH - dentry->d_inode->i_size; error = presto_reserve_space(fset->fset_cache, size); if (error) { EXIT; return error; } presto_getversion(&tgt_dir_ver, dir->d_inode); presto_getversion(&old_dir_ver, dentry->d_inode); handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_RMDIR); if ( IS_ERR(handle) ) { presto_release_space(fset->fset_cache, size); printk("ERROR: presto_do_rmdir: no space for transaction. Tell Peter.\n"); return -ENOSPC; } DQUOT_INIT(dir->d_inode); do_kml = presto_do_kml(info, dir->d_inode); do_expect = presto_do_expect(info, dir->d_inode); double_down(&dir->d_inode->i_zombie, &dentry->d_inode->i_zombie); d_unhash(dentry); if (IS_DEADDIR(dir->d_inode)) error = -ENOENT; else if (d_mountpoint(dentry)) error = -EBUSY; else { lock_kernel(); error = iops->rmdir(dir->d_inode, dentry); unlock_kernel(); if (!error) { dentry->d_inode->i_flags |= S_DEAD; error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME); } } double_up(&dir->d_inode->i_zombie, &dentry->d_inode->i_zombie); if (!error) d_delete(dentry); dput(dentry); presto_debug_fail_blkdev(fset, PRESTO_OP_RMDIR | 0x10); if ( !error && do_kml ) error = presto_journal_rmdir(&rec, fset, dir, &tgt_dir_ver, &old_dir_ver, dentry->d_name.len, dentry->d_name.name); presto_debug_fail_blkdev(fset, PRESTO_OP_RMDIR | 0x20); if ( !error && do_expect ) error = presto_write_last_rcvd(&rec, fset, info); presto_debug_fail_blkdev(fset, PRESTO_OP_RMDIR | 0x30); EXIT; presto_trans_commit(fset, handle); presto_release_space(fset->fset_cache, size); return error;}int lento_rmdir(const char *pathname, struct lento_vfs_context *info){ int error = 0; char * name; struct dentry *dentry; struct presto_file_set *fset; struct nameidata nd; ENTRY; name = getname(pathname); if(IS_ERR(name)) return PTR_ERR(name); if (path_init(name, LOOKUP_PARENT, &nd)) error = path_walk(name, &nd); if (error) goto exit; switch(nd.last_type) { case LAST_DOTDOT: error = -ENOTEMPTY; goto exit1; case LAST_ROOT: case LAST_DOT: error = -EBUSY; goto exit1; } down(&nd.dentry->d_inode->i_sem); dentry = lookup_hash(&nd.last, nd.dentry); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { fset = presto_fset(dentry); error = -EINVAL; if ( !fset ) { printk("No fileset!\n"); EXIT; goto exit_put; } error = presto_do_rmdir(fset, nd.dentry, dentry, info); exit_put: dput(dentry); } up(&nd.dentry->d_inode->i_sem);exit1: EXIT; path_release(&nd);exit: EXIT; putname(name); return error;}int presto_do_mknod(struct presto_file_set *fset, struct dentry *dir, struct dentry *dentry, int mode, dev_t dev, struct lento_vfs_context *info){ struct rec_info rec; int error = -EPERM; struct presto_version tgt_dir_ver, new_node_ver; struct inode_operations *iops; void *handle; ENTRY; down(&dir->d_inode->i_zombie); /* one KML entry */ error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); if (error) { EXIT; up(&dir->d_inode->i_zombie); return error; } if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) { EXIT; goto exit_lock; } error = may_create(dir->d_inode, dentry); if (error) { EXIT; goto exit_lock; } error = -EPERM; iops = filter_c2cdiops(fset->fset_cache->cache_filter); if (!iops->mknod) { EXIT; goto exit_lock; } DQUOT_INIT(dir->d_inode); lock_kernel(); error = -ENOSPC; presto_getversion(&tgt_dir_ver, dir->d_inode); handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_MKNOD); if ( IS_ERR(handle) ) { presto_release_space(fset->fset_cache, PRESTO_REQHIGH); printk("presto_do_mknod: no space for transaction\n"); goto exit_lock2; } error = iops->mknod(dir->d_inode, dentry, mode, dev); if (error) { EXIT; goto exit_commit; } if ( dentry->d_inode && dentry->d_inode->i_gid != presto_excluded_gid) { struct presto_cache *cache = fset->fset_cache; /* make it ours */ dentry->d_inode->i_op = filter_c2udiops(cache->cache_filter); filter_setup_dentry_ops(cache->cache_filter, dentry->d_op, &presto_dentry_ops); dentry->d_op = filter_c2udops(cache->cache_filter); /* if Lento does this, we won't have data */ if ( ISLENTO(presto_c2m(cache)) ) { presto_set(dentry, PRESTO_ATTR); } else { presto_set(dentry, PRESTO_ATTR | PRESTO_DATA); } } error = presto_settime(fset, dir, info, ATTR_MTIME); if (error) { EXIT; } error = presto_settime(fset, dentry, info, ATTR_CTIME | ATTR_MTIME); if (error) { EXIT; } presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x10); presto_getversion(&new_node_ver, dentry->d_inode); if ( presto_do_kml(info, dentry->d_inode) ) error = presto_journal_mknod(&rec, fset, dentry, &tgt_dir_ver, &new_node_ver, dentry->d_inode->i_mode, MAJOR(dev), MINOR(dev) ); presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x20); if ( presto_do_expect(info, dentry->d_inode) ) error = presto_write_last_rcvd(&rec, fset, info); presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x30); EXIT; exit_commit: presto_trans_commit(fset, handle); exit_lock2: unlock_kernel(); exit_lock: presto_release_space(fset->fset_cache, PRESTO_REQHIGH); up(&dir->d_inode->i_zombie); return error;}int lento_mknod(const char *filename, int mode, dev_t dev, struct lento_vfs_context *info){ int error = 0; char * tmp; struct dentry * dentry; struct nameidata nd; struct presto_file_set *fset; ENTRY; if (S_ISDIR(mode)) return -EPERM; tmp = getname(filename); if (IS_ERR(tmp)) return PTR_ERR(tmp); if (path_init(tmp, LOOKUP_PARENT, &nd)) error = path_walk(tmp, &nd); if (error) goto out; dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { fset = presto_fset(dentry); error = -EINVAL; if ( !fset ) { printk("No fileset!\n"); EXIT; goto exit_put; } switch (mode & S_IFMT) { case 0: case S_IFREG: error = -EOPNOTSUPP; break; case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: error = presto_do_mknod(fset, nd.dentry, dentry, mode, dev, info); break; case S_IFDIR: error = -EPERM; break; default: error = -EINVAL; } exit_put: dput(dentry); } up(&nd.dentry->d_inode->i_sem); path_release(&nd);out: putname(tmp); return error;}static int do_rename(struct presto_file_set *fset, struct dentry *old_parent, struct dentry *old_dentry, struct dentry *new_parent, struct dentry *new_dentry, struct lento_vfs_context *info){ struct rec_info rec; int error; struct inode_operations *iops; struct presto_version src_dir_ver, tgt_dir_ver; void *handle; int new_inode_unlink = 0; struct inode *old_dir = old_parent->d_inode; struct inode *new_dir = new_parent->d_inode; ENTRY; presto_getversion(&src_dir_ver, old_dir); presto_getversion(&tgt_dir_ver, new_dir); error = -EPERM; iops = filter_c2cdiops(fset->fset_cache->cache_filter); if (!iops || !iops->rename) { EXIT; return error; } error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); if (error) { EXIT; return error; } handle = presto_trans_start(fset, old_dir, PRESTO_OP_RENAME); if ( IS_ERR(handle) ) { presto_release_space(fset->fset_cache, PRESTO_REQHIGH); printk("presto_do_rename: no space for transaction\n"); return -ENOSPC; } if (new_dentry->d_inode && new_dentry->d_inode->i_nlink > 1) { dget(new_dentry); new_inode_unlink = 1; } error = iops->rename(old_dir, old_dentry, new_dir, new_dentry); if (error) { EXIT; goto exit; } if (new_inode_unlink) { error = presto_settime(fset, old_dentry, info, ATTR_CTIME); dput(old_dentry); if (error) { EXIT; goto exit; } } error = presto_settime(fset, old_parent, info, ATTR_CTIME | ATTR_MTIME); if (error) { EXIT; goto exit; } error = presto_settime(fset, new_parent, info, ATTR_CTIME | ATTR_MTIME); if (error) { EXIT; goto exit; } /* XXX make a distinction between cross file set * and intra file set renames here */ presto_debug_fail_blkdev(fset, PRESTO_OP_RENAME | 0x10); if ( presto_do_kml(info, old_dir) ) error = presto_journal_rename(&rec, fset, old_dentry, new_dentry, &src_dir_ver, &tgt_dir_ver); presto_debug_fail_blkdev(fset, PRESTO_OP_RENAME | 0x20); if ( presto_do_expect(info, new_dir) ) error = presto_write_last_rcvd(&rec, fset, info); presto_debug_fail_blkdev(fset, PRESTO_OP_RENAME | 0x30); EXIT;exit: presto_trans_commit(fset, handle); presto_release_space(fset->fset_cache, PRESTO_REQHIGH); return error;}staticint presto_rename_dir(struct presto_file_set *fset, struct dentry *old_parent, struct dentry *old_dentry, struct dentry *new_parent, struct dentry *new_dentry, struct lento_vfs_context *info){ int error; struct inode *target; struct inode *old_dir = old_parent->d_inode; struct inode *new_dir = new_parent->d_inode; if (old_dentry->d_inode == new_dentry->d_inode) return 0; error = may_delete(old_dir, old_dentry, 1); if (error) return error; if (new_dir->i_dev != old_dir->i_dev) return -EXDEV; if (!new_dentry->d_inode) error = may_create(new_dir, new_dentry); else error = may_delete(new_dir, new_dentry, 1); if (error) return error; if (!old_dir->i_op || !old_dir->i_op->rename) return -EPERM; /* * If we are going to change the parent - check write permissions, * we'll need to flip '..'. */ if (new_dir != old_dir) { error = permission(old_dentry->d_inode, MAY_WRITE); } if (error) return error; DQUOT_INIT(old_dir); DQUOT_INIT(new_dir); down(&old_dir->i_sb->s_vfs_rename_sem); error = -EINVAL; if (is_subdir(new_dentry, old_dentry)) goto out_unlock; target = new_dentry->d_inode; if (target) { /* Hastur! Hastur! Hastur! */ triple_down(&old_dir->i_zombie, &new_dir->i_zombie, &target->i_zombie); d_unhash(new_dentry); } else double_down(&old_dir->i_zombie, &new_dir->i_zombie);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -