📄 vfs_inode.c
字号:
inode = NULL; goto error; } result = v9fs_fid_add(dentry, fid); if (result < 0) goto error; if ((fid->qid.version) && (v9ses->cache)) dentry->d_op = &v9fs_cached_dentry_operations; else dentry->d_op = &v9fs_dentry_operations; d_add(dentry, inode); return NULL;error: if (fid) p9_client_clunk(fid); return ERR_PTR(result);}/** * v9fs_vfs_unlink - VFS unlink hook to delete an inode * @i: inode that is being unlinked * @d: dentry that is being unlinked * */static int v9fs_vfs_unlink(struct inode *i, struct dentry *d){ return v9fs_remove(i, d, 0);}/** * v9fs_vfs_rmdir - VFS unlink hook to delete a directory * @i: inode that is being unlinked * @d: dentry that is being unlinked * */static int v9fs_vfs_rmdir(struct inode *i, struct dentry *d){ return v9fs_remove(i, d, 1);}/** * v9fs_vfs_rename - VFS hook to rename an inode * @old_dir: old dir inode * @old_dentry: old dentry * @new_dir: new dir inode * @new_dentry: new dentry * */static intv9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry){ struct inode *old_inode; struct v9fs_session_info *v9ses; struct p9_fid *oldfid; struct p9_fid *olddirfid; struct p9_fid *newdirfid; struct p9_wstat wstat; int retval; P9_DPRINTK(P9_DEBUG_VFS, "\n"); retval = 0; old_inode = old_dentry->d_inode; v9ses = v9fs_inode2v9ses(old_inode); oldfid = v9fs_fid_lookup(old_dentry); if (IS_ERR(oldfid)) return PTR_ERR(oldfid); olddirfid = v9fs_fid_clone(old_dentry->d_parent); if (IS_ERR(olddirfid)) { retval = PTR_ERR(olddirfid); goto done; } newdirfid = v9fs_fid_clone(new_dentry->d_parent); if (IS_ERR(newdirfid)) { retval = PTR_ERR(newdirfid); goto clunk_olddir; } /* 9P can only handle file rename in the same directory */ if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) { P9_DPRINTK(P9_DEBUG_ERROR, "old dir and new dir are different\n"); retval = -EXDEV; goto clunk_newdir; } v9fs_blank_wstat(&wstat); wstat.muid = v9ses->uname; wstat.name = (char *) new_dentry->d_name.name; retval = p9_client_wstat(oldfid, &wstat);clunk_newdir: p9_client_clunk(newdirfid);clunk_olddir: p9_client_clunk(olddirfid);done: return retval;}/** * v9fs_vfs_getattr - retrieve file metadata * @mnt - mount information * @dentry - file to get attributes on * @stat - metadata structure to populate * */static intv9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat){ int err; struct v9fs_session_info *v9ses; struct p9_fid *fid; struct p9_stat *st; P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); err = -EPERM; v9ses = v9fs_inode2v9ses(dentry->d_inode); if (v9ses->cache == CACHE_LOOSE) return simple_getattr(mnt, dentry, stat); fid = v9fs_fid_lookup(dentry); if (IS_ERR(fid)) return PTR_ERR(fid); st = p9_client_stat(fid); if (IS_ERR(st)) return PTR_ERR(st); v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb); generic_fillattr(dentry->d_inode, stat); kfree(st); return 0;}/** * v9fs_vfs_setattr - set file metadata * @dentry: file whose metadata to set * @iattr: metadata assignment structure * */static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr){ int retval; struct v9fs_session_info *v9ses; struct p9_fid *fid; struct p9_wstat wstat; P9_DPRINTK(P9_DEBUG_VFS, "\n"); retval = -EPERM; v9ses = v9fs_inode2v9ses(dentry->d_inode); fid = v9fs_fid_lookup(dentry); if(IS_ERR(fid)) return PTR_ERR(fid); v9fs_blank_wstat(&wstat); if (iattr->ia_valid & ATTR_MODE) wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode); if (iattr->ia_valid & ATTR_MTIME) wstat.mtime = iattr->ia_mtime.tv_sec; if (iattr->ia_valid & ATTR_ATIME) wstat.atime = iattr->ia_atime.tv_sec; if (iattr->ia_valid & ATTR_SIZE) wstat.length = iattr->ia_size; if (v9fs_extended(v9ses)) { if (iattr->ia_valid & ATTR_UID) wstat.n_uid = iattr->ia_uid; if (iattr->ia_valid & ATTR_GID) wstat.n_gid = iattr->ia_gid; } retval = p9_client_wstat(fid, &wstat); if (retval >= 0) retval = inode_setattr(dentry->d_inode, iattr); return retval;}/** * v9fs_stat2inode - populate an inode structure with mistat info * @stat: Plan 9 metadata (mistat) structure * @inode: inode to populate * @sb: superblock of filesystem * */voidv9fs_stat2inode(struct p9_stat *stat, struct inode *inode, struct super_block *sb){ int n; char ext[32]; struct v9fs_session_info *v9ses = sb->s_fs_info; inode->i_nlink = 1; inode->i_atime.tv_sec = stat->atime; inode->i_mtime.tv_sec = stat->mtime; inode->i_ctime.tv_sec = stat->mtime; inode->i_uid = v9ses->dfltuid; inode->i_gid = v9ses->dfltgid; if (v9fs_extended(v9ses)) { inode->i_uid = stat->n_uid; inode->i_gid = stat->n_gid; } inode->i_mode = p9mode2unixmode(v9ses, stat->mode); if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { char type = 0; int major = -1; int minor = -1; n = stat->extension.len; if (n > sizeof(ext)-1) n = sizeof(ext)-1; memmove(ext, stat->extension.str, n); ext[n] = 0; sscanf(ext, "%c %u %u", &type, &major, &minor); switch (type) { case 'c': inode->i_mode &= ~S_IFBLK; inode->i_mode |= S_IFCHR; break; case 'b': break; default: P9_DPRINTK(P9_DEBUG_ERROR, "Unknown special type %c (%.*s)\n", type, stat->extension.len, stat->extension.str); }; inode->i_rdev = MKDEV(major, minor); } else inode->i_rdev = 0; inode->i_size = stat->length; /* not real number of blocks, but 512 byte ones ... */ inode->i_blocks = (inode->i_size + 512 - 1) >> 9;}/** * v9fs_qid2ino - convert qid into inode number * @qid: qid to hash * * BUG: potential for inode number collisions? */ino_t v9fs_qid2ino(struct p9_qid *qid){ u64 path = qid->path + 2; ino_t i = 0; if (sizeof(ino_t) == sizeof(path)) memcpy(&i, &path, sizeof(ino_t)); else i = (ino_t) (path ^ (path >> 32)); return i;}/** * v9fs_readlink - read a symlink's location (internal version) * @dentry: dentry for symlink * @buffer: buffer to load symlink location into * @buflen: length of buffer * */static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen){ int retval; struct v9fs_session_info *v9ses; struct p9_fid *fid; struct p9_stat *st; P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name); retval = -EPERM; v9ses = v9fs_inode2v9ses(dentry->d_inode); fid = v9fs_fid_lookup(dentry); if (IS_ERR(fid)) return PTR_ERR(fid); if (!v9fs_extended(v9ses)) return -EBADF; st = p9_client_stat(fid); if (IS_ERR(st)) return PTR_ERR(st); if (!(st->mode & P9_DMSYMLINK)) { retval = -EINVAL; goto done; } /* copy extension buffer into buffer */ if (st->extension.len < buflen) buflen = st->extension.len + 1; memmove(buffer, st->extension.str, buflen - 1); buffer[buflen-1] = 0; P9_DPRINTK(P9_DEBUG_VFS, "%s -> %.*s (%s)\n", dentry->d_name.name, st->extension.len, st->extension.str, buffer); retval = buflen;done: kfree(st); return retval;}/** * v9fs_vfs_readlink - read a symlink's location * @dentry: dentry for symlink * @buf: buffer to load symlink location into * @buflen: length of buffer * */static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer, int buflen){ int retval; int ret; char *link = __getname(); if (unlikely(!link)) return -ENOMEM; if (buflen > PATH_MAX) buflen = PATH_MAX; P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); retval = v9fs_readlink(dentry, link, buflen); if (retval > 0) { if ((ret = copy_to_user(buffer, link, retval)) != 0) { P9_DPRINTK(P9_DEBUG_ERROR, "problem copying to user: %d\n", ret); retval = ret; } } __putname(link); return retval;}/** * v9fs_vfs_follow_link - follow a symlink path * @dentry: dentry for symlink * @nd: nameidata * */static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd){ int len = 0; char *link = __getname(); P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name); if (!link) link = ERR_PTR(-ENOMEM); else { len = v9fs_readlink(dentry, link, PATH_MAX); if (len < 0) { __putname(link); link = ERR_PTR(len); } else link[len] = 0; } nd_set_link(nd, link); return NULL;}/** * v9fs_vfs_put_link - release a symlink path * @dentry: dentry for symlink * @nd: nameidata * */static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p){ char *s = nd_get_link(nd); P9_DPRINTK(P9_DEBUG_VFS, " %s %s\n", dentry->d_name.name, s); if (!IS_ERR(s)) __putname(s);}static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, int mode, const char *extension){ u32 perm; struct v9fs_session_info *v9ses; struct p9_fid *fid; v9ses = v9fs_inode2v9ses(dir); if (!v9fs_extended(v9ses)) { P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n"); return -EPERM; } perm = unixmode2p9mode(v9ses, mode); fid = v9fs_create(v9ses, dir, dentry, (char *) extension, perm, P9_OREAD); if (IS_ERR(fid)) return PTR_ERR(fid); p9_client_clunk(fid); return 0;}/** * v9fs_vfs_symlink - helper function to create symlinks * @dir: directory inode containing symlink * @dentry: dentry for symlink * @symname: symlink data * * See 9P2000.u RFC for more information * */static intv9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname){ P9_DPRINTK(P9_DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, symname); return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname);}/** * v9fs_vfs_link - create a hardlink * @old_dentry: dentry for file to link to * @dir: inode destination for new link * @dentry: dentry for link * *//* XXX - lots of code dup'd from symlink and creates, * figure out a better reuse strategy */static intv9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry){ int retval; struct p9_fid *oldfid; char *name; P9_DPRINTK(P9_DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, old_dentry->d_name.name); oldfid = v9fs_fid_clone(old_dentry); if (IS_ERR(oldfid)) return PTR_ERR(oldfid); name = __getname(); if (unlikely(!name)) { retval = -ENOMEM; goto clunk_fid; } sprintf(name, "%d\n", oldfid->fid); retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name); __putname(name);clunk_fid: p9_client_clunk(oldfid); return retval;}/** * v9fs_vfs_mknod - create a special file * @dir: inode destination for new link * @dentry: dentry for file * @mode: mode for creation * @dev_t: device associated with special file * */static intv9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev){ int retval; char *name; P9_DPRINTK(P9_DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); if (!new_valid_dev(rdev)) return -EINVAL; name = __getname(); if (!name) return -ENOMEM; /* build extension */ if (S_ISBLK(mode)) sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev)); else if (S_ISCHR(mode)) sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev)); else if (S_ISFIFO(mode)) *name = 0; else { __putname(name); return -EINVAL; } retval = v9fs_vfs_mkspecial(dir, dentry, mode, name); __putname(name); return retval;}static const struct inode_operations v9fs_dir_inode_operations_ext = { .create = v9fs_vfs_create, .lookup = v9fs_vfs_lookup, .symlink = v9fs_vfs_symlink, .link = v9fs_vfs_link, .unlink = v9fs_vfs_unlink, .mkdir = v9fs_vfs_mkdir, .rmdir = v9fs_vfs_rmdir, .mknod = v9fs_vfs_mknod, .rename = v9fs_vfs_rename, .readlink = v9fs_vfs_readlink, .getattr = v9fs_vfs_getattr, .setattr = v9fs_vfs_setattr,};static const struct inode_operations v9fs_dir_inode_operations = { .create = v9fs_vfs_create, .lookup = v9fs_vfs_lookup, .unlink = v9fs_vfs_unlink, .mkdir = v9fs_vfs_mkdir, .rmdir = v9fs_vfs_rmdir, .mknod = v9fs_vfs_mknod, .rename = v9fs_vfs_rename, .getattr = v9fs_vfs_getattr, .setattr = v9fs_vfs_setattr,};static const struct inode_operations v9fs_file_inode_operations = { .getattr = v9fs_vfs_getattr, .setattr = v9fs_vfs_setattr,};static const struct inode_operations v9fs_symlink_inode_operations = { .readlink = v9fs_vfs_readlink, .follow_link = v9fs_vfs_follow_link, .put_link = v9fs_vfs_put_link, .getattr = v9fs_vfs_getattr, .setattr = v9fs_vfs_setattr,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -