📄 ops_inode.c
字号:
if (ip == nip) return 0; } /* Make sure we aren't trying to move a dirctory into it's subdir */ if (S_ISDIR(ip->i_inode.i_mode) && odip != ndip) { dir_rename = 1; error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, 0, &r_gh); if (error) goto out; error = gfs2_ok_to_move(ip, ndip); if (error) goto out_gunlock_r; } num_gh = 1; gfs2_holder_init(odip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); if (odip != ndip) { gfs2_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); num_gh++; } gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); num_gh++; if (nip) { gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh); num_gh++; /* grab the resource lock for unlink flag twiddling * this is the case of the target file already existing * so we unlink before doing the rename */ nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr); if (nrgd) gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++); } error = gfs2_glock_nq_m(num_gh, ghs); if (error) goto out_uninit; /* Check out the old directory */ error = gfs2_unlink_ok(odip, &odentry->d_name, ip); if (error) goto out_gunlock; /* Check out the new directory */ if (nip) { error = gfs2_unlink_ok(ndip, &ndentry->d_name, nip); if (error) goto out_gunlock; if (S_ISDIR(nip->i_inode.i_mode)) { if (nip->i_di.di_entries < 2) { if (gfs2_consist_inode(nip)) gfs2_dinode_print(nip); error = -EIO; goto out_gunlock; } if (nip->i_di.di_entries > 2) { error = -ENOTEMPTY; goto out_gunlock; } } } else { error = permission(ndir, MAY_WRITE | MAY_EXEC, NULL); if (error) goto out_gunlock; error = gfs2_dir_check(ndir, &ndentry->d_name, NULL); switch (error) { case -ENOENT: error = 0; break; case 0: error = -EEXIST; default: goto out_gunlock; }; if (odip != ndip) { if (!ndip->i_inode.i_nlink) { error = -EINVAL; goto out_gunlock; } if (ndip->i_di.di_entries == (u32)-1) { error = -EFBIG; goto out_gunlock; } if (S_ISDIR(ip->i_inode.i_mode) && ndip->i_inode.i_nlink == (u32)-1) { error = -EMLINK; goto out_gunlock; } } } /* Check out the dir to be renamed */ if (dir_rename) { error = permission(odentry->d_inode, MAY_WRITE, NULL); if (error) goto out_gunlock; } alloc_required = error = gfs2_diradd_alloc_required(ndir, &ndentry->d_name); if (error < 0) goto out_gunlock; error = 0; if (alloc_required) { struct gfs2_alloc *al = gfs2_alloc_get(ndip); error = gfs2_quota_lock(ndip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) goto out_alloc; error = gfs2_quota_check(ndip, ndip->i_inode.i_uid, ndip->i_inode.i_gid); if (error) goto out_gunlock_q; al->al_requested = sdp->sd_max_dirres; error = gfs2_inplace_reserve(ndip); if (error) goto out_gunlock_q; error = gfs2_trans_begin(sdp, sdp->sd_max_dirres + al->al_rgd->rd_length + 4 * RES_DINODE + 4 * RES_LEAF + RES_STATFS + RES_QUOTA + 4, 0); if (error) goto out_ipreserv; } else { error = gfs2_trans_begin(sdp, 4 * RES_DINODE + 5 * RES_LEAF + 4, 0); if (error) goto out_gunlock; } /* Remove the target file, if it exists */ if (nip) { if (S_ISDIR(nip->i_inode.i_mode)) error = gfs2_rmdiri(ndip, &ndentry->d_name, nip); else { error = gfs2_dir_del(ndip, &ndentry->d_name); if (error) goto out_end_trans; error = gfs2_change_nlink(nip, -1); } if (error) goto out_end_trans; } if (dir_rename) { struct qstr name; gfs2_str2qstr(&name, ".."); error = gfs2_change_nlink(ndip, +1); if (error) goto out_end_trans; error = gfs2_change_nlink(odip, -1); if (error) goto out_end_trans; error = gfs2_dir_mvino(ip, &name, ndip, DT_DIR); if (error) goto out_end_trans; } else { struct buffer_head *dibh; error = gfs2_meta_inode_buffer(ip, &dibh); if (error) goto out_end_trans; ip->i_inode.i_ctime = CURRENT_TIME; gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } error = gfs2_dir_del(odip, &odentry->d_name); if (error) goto out_end_trans; error = gfs2_dir_add(ndir, &ndentry->d_name, ip, IF2DT(ip->i_inode.i_mode)); if (error) goto out_end_trans;out_end_trans: gfs2_trans_end(sdp);out_ipreserv: if (alloc_required) gfs2_inplace_release(ndip);out_gunlock_q: if (alloc_required) gfs2_quota_unlock(ndip);out_alloc: if (alloc_required) gfs2_alloc_put(ndip);out_gunlock: gfs2_glock_dq_m(num_gh, ghs);out_uninit: for (x = 0; x < num_gh; x++) gfs2_holder_uninit(ghs + x);out_gunlock_r: if (dir_rename) gfs2_glock_dq_uninit(&r_gh);out: return error;}/** * gfs2_readlink - Read the value of a symlink * @dentry: the symlink * @buf: the buffer to read the symlink data into * @size: the size of the buffer * * Returns: errno */static int gfs2_readlink(struct dentry *dentry, char __user *user_buf, int user_size){ struct gfs2_inode *ip = GFS2_I(dentry->d_inode); char array[GFS2_FAST_NAME_SIZE], *buf = array; unsigned int len = GFS2_FAST_NAME_SIZE; int error; error = gfs2_readlinki(ip, &buf, &len); if (error) return error; if (user_size > len - 1) user_size = len - 1; if (copy_to_user(user_buf, buf, user_size)) error = -EFAULT; else error = user_size; if (buf != array) kfree(buf); return error;}/** * gfs2_follow_link - Follow a symbolic link * @dentry: The dentry of the link * @nd: Data that we pass to vfs_follow_link() * * This can handle symlinks of any size. It is optimised for symlinks * under GFS2_FAST_NAME_SIZE. * * Returns: 0 on success or error code */static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd){ struct gfs2_inode *ip = GFS2_I(dentry->d_inode); char array[GFS2_FAST_NAME_SIZE], *buf = array; unsigned int len = GFS2_FAST_NAME_SIZE; int error; error = gfs2_readlinki(ip, &buf, &len); if (!error) { error = vfs_follow_link(nd, buf); if (buf != array) kfree(buf); } return ERR_PTR(error);}/** * gfs2_permission - * @inode: * @mask: * @nd: passed from Linux VFS, ignored by us * * This may be called from the VFS directly, or from within GFS2 with the * inode locked, so we look to see if the glock is already locked and only * lock the glock if its not already been done. * * Returns: errno */static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd){ struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder i_gh; int error; int unlock = 0; if (gfs2_glock_is_locked_by_me(ip->i_gl) == 0) { error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) return error; unlock = 1; } error = generic_permission(inode, mask, gfs2_check_acl); if (unlock) gfs2_glock_dq_uninit(&i_gh); return error;}static int setattr_size(struct inode *inode, struct iattr *attr){ struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); int error; if (attr->ia_size != ip->i_di.di_size) { error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); if (error) return error; error = vmtruncate(inode, attr->ia_size); gfs2_trans_end(sdp); if (error) return error; } error = gfs2_truncatei(ip, attr->ia_size); if (error && (inode->i_size != ip->i_di.di_size)) i_size_write(inode, ip->i_di.di_size); return error;}static int setattr_chown(struct inode *inode, struct iattr *attr){ struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); struct buffer_head *dibh; u32 ouid, ogid, nuid, ngid; int error; ouid = inode->i_uid; ogid = inode->i_gid; nuid = attr->ia_uid; ngid = attr->ia_gid; if (!(attr->ia_valid & ATTR_UID) || ouid == nuid) ouid = nuid = NO_QUOTA_CHANGE; if (!(attr->ia_valid & ATTR_GID) || ogid == ngid) ogid = ngid = NO_QUOTA_CHANGE; gfs2_alloc_get(ip); error = gfs2_quota_lock(ip, nuid, ngid); if (error) goto out_alloc; if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { error = gfs2_quota_check(ip, nuid, ngid); if (error) goto out_gunlock_q; } error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_QUOTA, 0); if (error) goto out_gunlock_q; error = gfs2_meta_inode_buffer(ip, &dibh); if (error) goto out_end_trans; error = inode_setattr(inode, attr); gfs2_assert_warn(sdp, !error); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { gfs2_quota_change(ip, -ip->i_di.di_blocks, ouid, ogid); gfs2_quota_change(ip, ip->i_di.di_blocks, nuid, ngid); }out_end_trans: gfs2_trans_end(sdp);out_gunlock_q: gfs2_quota_unlock(ip);out_alloc: gfs2_alloc_put(ip); return error;}/** * gfs2_setattr - Change attributes on an inode * @dentry: The dentry which is changing * @attr: The structure describing the change * * The VFS layer wants to change one or more of an inodes attributes. Write * that change out to disk. * * Returns: errno */static int gfs2_setattr(struct dentry *dentry, struct iattr *attr){ struct inode *inode = dentry->d_inode; struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder i_gh; int error; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); if (error) return error; error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out; error = inode_change_ok(inode, attr); if (error) goto out; if (attr->ia_valid & ATTR_SIZE) error = setattr_size(inode, attr); else if (attr->ia_valid & (ATTR_UID | ATTR_GID)) error = setattr_chown(inode, attr); else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode)) error = gfs2_acl_chmod(ip, attr); else error = gfs2_setattr_simple(ip, attr);out: gfs2_glock_dq_uninit(&i_gh); if (!error) mark_inode_dirty(inode); return error;}/** * gfs2_getattr - Read out an inode's attributes * @mnt: The vfsmount the inode is being accessed from * @dentry: The dentry to stat * @stat: The inode's stats * * This may be called from the VFS directly, or from within GFS2 with the * inode locked, so we look to see if the glock is already locked and only * lock the glock if its not already been done. Note that its the NFS * readdirplus operation which causes this to be called (from filldir) * with the glock already held. * * Returns: errno */static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat){ struct inode *inode = dentry->d_inode; struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_holder gh; int error; int unlock = 0; if (gfs2_glock_is_locked_by_me(ip->i_gl) == 0) { error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); if (error) return error; unlock = 1; } generic_fillattr(inode, stat); if (unlock) gfs2_glock_dq_uninit(&gh); return 0;}static int gfs2_setxattr(struct dentry *dentry, const char *name, const void *data, size_t size, int flags){ struct inode *inode = dentry->d_inode; struct gfs2_ea_request er; memset(&er, 0, sizeof(struct gfs2_ea_request)); er.er_type = gfs2_ea_name2type(name, &er.er_name); if (er.er_type == GFS2_EATYPE_UNUSED) return -EOPNOTSUPP; er.er_data = (char *)data; er.er_name_len = strlen(er.er_name); er.er_data_len = size; er.er_flags = flags; gfs2_assert_warn(GFS2_SB(inode), !(er.er_flags & GFS2_ERF_MODE)); return gfs2_ea_set(GFS2_I(inode), &er);}static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name, void *data, size_t size){ struct gfs2_ea_request er; memset(&er, 0, sizeof(struct gfs2_ea_request)); er.er_type = gfs2_ea_name2type(name, &er.er_name); if (er.er_type == GFS2_EATYPE_UNUSED) return -EOPNOTSUPP; er.er_data = data; er.er_name_len = strlen(er.er_name); er.er_data_len = size; return gfs2_ea_get(GFS2_I(dentry->d_inode), &er);}static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size){ struct gfs2_ea_request er; memset(&er, 0, sizeof(struct gfs2_ea_request)); er.er_data = (size) ? buffer : NULL; er.er_data_len = size; return gfs2_ea_list(GFS2_I(dentry->d_inode), &er);}static int gfs2_removexattr(struct dentry *dentry, const char *name){ struct gfs2_ea_request er; memset(&er, 0, sizeof(struct gfs2_ea_request)); er.er_type = gfs2_ea_name2type(name, &er.er_name); if (er.er_type == GFS2_EATYPE_UNUSED) return -EOPNOTSUPP; er.er_name_len = strlen(er.er_name); return gfs2_ea_remove(GFS2_I(dentry->d_inode), &er);}const struct inode_operations gfs2_file_iops = { .permission = gfs2_permission, .setattr = gfs2_setattr, .getattr = gfs2_getattr, .setxattr = gfs2_setxattr, .getxattr = gfs2_getxattr, .listxattr = gfs2_listxattr, .removexattr = gfs2_removexattr,};const struct inode_operations gfs2_dev_iops = { .permission = gfs2_permission, .setattr = gfs2_setattr, .getattr = gfs2_getattr, .setxattr = gfs2_setxattr, .getxattr = gfs2_getxattr, .listxattr = gfs2_listxattr, .removexattr = gfs2_removexattr,};const struct inode_operations gfs2_dir_iops = { .create = gfs2_create, .lookup = gfs2_lookup, .link = gfs2_link, .unlink = gfs2_unlink, .symlink = gfs2_symlink, .mkdir = gfs2_mkdir, .rmdir = gfs2_rmdir, .mknod = gfs2_mknod, .rename = gfs2_rename, .permission = gfs2_permission, .setattr = gfs2_setattr, .getattr = gfs2_getattr, .setxattr = gfs2_setxattr, .getxattr = gfs2_getxattr, .listxattr = gfs2_listxattr, .removexattr = gfs2_removexattr,};const struct inode_operations gfs2_symlink_iops = { .readlink = gfs2_readlink, .follow_link = gfs2_follow_link, .permission = gfs2_permission, .setattr = gfs2_setattr, .getattr = gfs2_getattr, .setxattr = gfs2_setxattr, .getxattr = gfs2_getxattr, .listxattr = gfs2_listxattr, .removexattr = gfs2_removexattr,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -