📄 eattr.c
字号:
{ struct ea_set es; unsigned int blks = 2; int error; memset(&es, 0, sizeof(struct ea_set)); es.es_er = er; es.es_el = el; error = ea_foreach(ip, ea_set_simple, &es); if (error > 0) return 0; if (error) return error; if (!(ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT)) blks++; if (GFS2_EAREQ_SIZE_STUFFED(er) > GFS2_SB(&ip->i_inode)->sd_jbsize) blks += DIV_ROUND_UP(er->er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize); return ea_alloc_skeleton(ip, er, blks, ea_set_block, el);}static int ea_set_remove_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el){ if (el->el_prev && GFS2_EA2NEXT(el->el_prev) != el->el_ea) { el->el_prev = GFS2_EA2NEXT(el->el_prev); gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), GFS2_EA2NEXT(el->el_prev) == el->el_ea); } return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev,0);}int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er){ struct gfs2_ea_location el; int error; if (!ip->i_di.di_eattr) { if (er->er_flags & XATTR_REPLACE) return -ENODATA; return ea_init(ip, er); } error = gfs2_ea_find(ip, er, &el); if (error) return error; if (el.el_ea) { if (ip->i_di.di_flags & GFS2_DIF_APPENDONLY) { brelse(el.el_bh); return -EPERM; } error = -EEXIST; if (!(er->er_flags & XATTR_CREATE)) { int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea); error = ea_set_i(ip, er, &el); if (!error && unstuffed) ea_set_remove_unstuffed(ip, &el); } brelse(el.el_bh); } else { error = -ENODATA; if (!(er->er_flags & XATTR_REPLACE)) error = ea_set_i(ip, er, NULL); } return error;}int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er){ struct gfs2_holder i_gh; int error; if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN) return -EINVAL; if (!er->er_data || !er->er_data_len) { er->er_data = NULL; er->er_data_len = 0; } error = ea_check_size(GFS2_SB(&ip->i_inode), er); if (error) return error; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); if (error) return error; if (IS_IMMUTABLE(&ip->i_inode)) error = -EPERM; else error = gfs2_ea_ops[er->er_type]->eo_set(ip, er); gfs2_glock_dq_uninit(&i_gh); return error;}static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el){ struct gfs2_ea_header *ea = el->el_ea; struct gfs2_ea_header *prev = el->el_prev; struct buffer_head *dibh; int error; error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0); if (error) return error; gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1); if (prev) { u32 len; len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea); prev->ea_rec_len = cpu_to_be32(len); if (GFS2_EA_IS_LAST(ea)) prev->ea_flags |= GFS2_EAFLAG_LAST; } else ea->ea_type = GFS2_EATYPE_UNUSED; error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { 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); } gfs2_trans_end(GFS2_SB(&ip->i_inode)); return error;}int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er){ struct gfs2_ea_location el; int error; if (!ip->i_di.di_eattr) return -ENODATA; error = gfs2_ea_find(ip, er, &el); if (error) return error; if (!el.el_ea) return -ENODATA; if (GFS2_EA_IS_STUFFED(el.el_ea)) error = ea_remove_stuffed(ip, &el); else error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev, 0); brelse(el.el_bh); return error;}/** * gfs2_ea_remove - sets (or creates or replaces) an extended attribute * @ip: pointer to the inode of the target file * @er: request information * * Returns: errno */int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er){ struct gfs2_holder i_gh; int error; if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN) return -EINVAL; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); if (error) return error; if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode)) error = -EPERM; else error = gfs2_ea_ops[er->er_type]->eo_remove(ip, er); gfs2_glock_dq_uninit(&i_gh); return error;}static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea, char *data){ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head **bh; unsigned int amount = GFS2_EA_DATA_LEN(ea); unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize); __be64 *dataptrs = GFS2_EA2DATAPTRS(ea); unsigned int x; int error; bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_KERNEL); if (!bh) return -ENOMEM; error = gfs2_trans_begin(sdp, nptrs + RES_DINODE, 0); if (error) goto out; for (x = 0; x < nptrs; x++) { error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0, bh + x); if (error) { while (x--) brelse(bh[x]); goto fail; } dataptrs++; } for (x = 0; x < nptrs; x++) { error = gfs2_meta_wait(sdp, bh[x]); if (error) { for (; x < nptrs; x++) brelse(bh[x]); goto fail; } if (gfs2_metatype_check(sdp, bh[x], GFS2_METATYPE_ED)) { for (; x < nptrs; x++) brelse(bh[x]); error = -EIO; goto fail; } gfs2_trans_add_bh(ip->i_gl, bh[x], 1); memcpy(bh[x]->b_data + sizeof(struct gfs2_meta_header), data, (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize); amount -= sdp->sd_jbsize; data += sdp->sd_jbsize; brelse(bh[x]); }out: kfree(bh); return error;fail: gfs2_trans_end(sdp); kfree(bh); return error;}int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el, struct iattr *attr, char *data){ struct buffer_head *dibh; int error; if (GFS2_EA_IS_STUFFED(el->el_ea)) { error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0); if (error) return error; gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1); memcpy(GFS2_EA2DATA(el->el_ea), data, GFS2_EA_DATA_LEN(el->el_ea)); } else error = ea_acl_chmod_unstuffed(ip, el->el_ea, data); if (error) return error; error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { error = inode_setattr(&ip->i_inode, attr); gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } gfs2_trans_end(GFS2_SB(&ip->i_inode)); return error;}static int ea_dealloc_indirect(struct gfs2_inode *ip){ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_rgrp_list rlist; struct buffer_head *indbh, *dibh; __be64 *eablk, *end; unsigned int rg_blocks = 0; u64 bstart = 0; unsigned int blen = 0; unsigned int blks = 0; unsigned int x; int error; memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, &indbh); if (error) return error; if (gfs2_metatype_check(sdp, indbh, GFS2_METATYPE_IN)) { error = -EIO; goto out; } eablk = (__be64 *)(indbh->b_data + sizeof(struct gfs2_meta_header)); end = eablk + sdp->sd_inptrs; for (; eablk < end; eablk++) { u64 bn; if (!*eablk) break; bn = be64_to_cpu(*eablk); if (bstart + blen == bn) blen++; else { if (bstart) gfs2_rlist_add(sdp, &rlist, bstart); bstart = bn; blen = 1; } blks++; } if (bstart) gfs2_rlist_add(sdp, &rlist, bstart); else goto out; gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0); for (x = 0; x < rlist.rl_rgrps; x++) { struct gfs2_rgrpd *rgd; rgd = rlist.rl_ghs[x].gh_gl->gl_object; rg_blocks += rgd->rd_length; } error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs); if (error) goto out_rlist_free; error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE + RES_INDIRECT + RES_STATFS + RES_QUOTA, blks); if (error) goto out_gunlock; gfs2_trans_add_bh(ip->i_gl, indbh, 1); eablk = (__be64 *)(indbh->b_data + sizeof(struct gfs2_meta_header)); bstart = 0; blen = 0; for (; eablk < end; eablk++) { u64 bn; if (!*eablk) break; bn = be64_to_cpu(*eablk); if (bstart + blen == bn) blen++; else { if (bstart) gfs2_free_meta(ip, bstart, blen); bstart = bn; blen = 1; } *eablk = 0; if (!ip->i_di.di_blocks) gfs2_consist_inode(ip); ip->i_di.di_blocks--; gfs2_set_inode_blocks(&ip->i_inode); } if (bstart) gfs2_free_meta(ip, bstart, blen); ip->i_di.di_flags &= ~GFS2_DIF_EA_INDIRECT; error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } gfs2_trans_end(sdp);out_gunlock: gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);out_rlist_free: gfs2_rlist_free(&rlist);out: brelse(indbh); return error;}static int ea_dealloc_block(struct gfs2_inode *ip){ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_alloc *al = &ip->i_alloc; struct gfs2_rgrpd *rgd; struct buffer_head *dibh; int error; rgd = gfs2_blk2rgrpd(sdp, ip->i_di.di_eattr); if (!rgd) { gfs2_consist_inode(ip); return -EIO; } error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &al->al_rgd_gh); if (error) return error; error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_DINODE + RES_STATFS + RES_QUOTA, 1); if (error) goto out_gunlock; gfs2_free_meta(ip, ip->i_di.di_eattr, 1); ip->i_di.di_eattr = 0; if (!ip->i_di.di_blocks) gfs2_consist_inode(ip); ip->i_di.di_blocks--; gfs2_set_inode_blocks(&ip->i_inode); error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { gfs2_trans_add_bh(ip->i_gl, dibh, 1); gfs2_dinode_out(ip, dibh->b_data); brelse(dibh); } gfs2_trans_end(sdp);out_gunlock: gfs2_glock_dq_uninit(&al->al_rgd_gh); return error;}/** * gfs2_ea_dealloc - deallocate the extended attribute fork * @ip: the inode * * Returns: errno */int gfs2_ea_dealloc(struct gfs2_inode *ip){ struct gfs2_alloc *al; int error; al = gfs2_alloc_get(ip); error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) goto out_alloc; error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh); if (error) goto out_quota; error = ea_foreach(ip, ea_dealloc_unstuffed, NULL); if (error) goto out_rindex; if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) { error = ea_dealloc_indirect(ip); if (error) goto out_rindex; } error = ea_dealloc_block(ip);out_rindex: gfs2_glock_dq_uninit(&al->al_ri_gh);out_quota: gfs2_quota_unhold(ip);out_alloc: gfs2_alloc_put(ip); return error;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -