📄 eattr.c
字号:
/** * gfs2_ea_get_i - * @ip: The GFS2 inode * @er: The request structure * * Returns: actual size of data on success, -errno on error */int gfs2_ea_get_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 (er->er_data_len) { if (GFS2_EA_DATA_LEN(el.el_ea) > er->er_data_len) error = -ERANGE; else error = gfs2_ea_get_copy(ip, &el, er->er_data); } if (!error) error = GFS2_EA_DATA_LEN(el.el_ea); brelse(el.el_bh); return error;}/** * gfs2_ea_get - * @ip: The GFS2 inode * @er: The request structure * * Returns: actual size of data on success, -errno on error */int gfs2_ea_get(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 = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); if (error) return error; error = gfs2_ea_ops[er->er_type]->eo_get(ip, er); gfs2_glock_dq_uninit(&i_gh); return error;}/** * ea_alloc_blk - allocates a new block for extended attributes. * @ip: A pointer to the inode that's getting extended attributes * @bhp: Pointer to pointer to a struct buffer_head * * Returns: errno */static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp){ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_ea_header *ea; u64 block; block = gfs2_alloc_meta(ip); *bhp = gfs2_meta_new(ip->i_gl, block); gfs2_trans_add_bh(ip->i_gl, *bhp, 1); gfs2_metatype_set(*bhp, GFS2_METATYPE_EA, GFS2_FORMAT_EA); gfs2_buffer_clear_tail(*bhp, sizeof(struct gfs2_meta_header)); ea = GFS2_EA_BH2FIRST(*bhp); ea->ea_rec_len = cpu_to_be32(sdp->sd_jbsize); ea->ea_type = GFS2_EATYPE_UNUSED; ea->ea_flags = GFS2_EAFLAG_LAST; ea->ea_num_ptrs = 0; ip->i_di.di_blocks++; gfs2_set_inode_blocks(&ip->i_inode); return 0;}/** * ea_write - writes the request info to an ea, creating new blocks if * necessary * @ip: inode that is being modified * @ea: the location of the new ea in a block * @er: the write request * * Note: does not update ea_rec_len or the GFS2_EAFLAG_LAST bin of ea_flags * * returns : errno */static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea, struct gfs2_ea_request *er){ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); ea->ea_data_len = cpu_to_be32(er->er_data_len); ea->ea_name_len = er->er_name_len; ea->ea_type = er->er_type; ea->__pad = 0; memcpy(GFS2_EA2NAME(ea), er->er_name, er->er_name_len); if (GFS2_EAREQ_SIZE_STUFFED(er) <= sdp->sd_jbsize) { ea->ea_num_ptrs = 0; memcpy(GFS2_EA2DATA(ea), er->er_data, er->er_data_len); } else { __be64 *dataptr = GFS2_EA2DATAPTRS(ea); const char *data = er->er_data; unsigned int data_len = er->er_data_len; unsigned int copy; unsigned int x; ea->ea_num_ptrs = DIV_ROUND_UP(er->er_data_len, sdp->sd_jbsize); for (x = 0; x < ea->ea_num_ptrs; x++) { struct buffer_head *bh; u64 block; int mh_size = sizeof(struct gfs2_meta_header); block = gfs2_alloc_meta(ip); bh = gfs2_meta_new(ip->i_gl, block); gfs2_trans_add_bh(ip->i_gl, bh, 1); gfs2_metatype_set(bh, GFS2_METATYPE_ED, GFS2_FORMAT_ED); ip->i_di.di_blocks++; gfs2_set_inode_blocks(&ip->i_inode); copy = data_len > sdp->sd_jbsize ? sdp->sd_jbsize : data_len; memcpy(bh->b_data + mh_size, data, copy); if (copy < sdp->sd_jbsize) memset(bh->b_data + mh_size + copy, 0, sdp->sd_jbsize - copy); *dataptr++ = cpu_to_be64(bh->b_blocknr); data += copy; data_len -= copy; brelse(bh); } gfs2_assert_withdraw(sdp, !data_len); } return 0;}typedef int (*ea_skeleton_call_t) (struct gfs2_inode *ip, struct gfs2_ea_request *er, void *private);static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er, unsigned int blks, ea_skeleton_call_t skeleton_call, void *private){ struct gfs2_alloc *al; struct buffer_head *dibh; int error; al = gfs2_alloc_get(ip); error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE); if (error) goto out; error = gfs2_quota_check(ip, ip->i_inode.i_uid, ip->i_inode.i_gid); if (error) goto out_gunlock_q; al->al_requested = blks; error = gfs2_inplace_reserve(ip); if (error) goto out_gunlock_q; error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), blks + al->al_rgd->rd_length + RES_DINODE + RES_STATFS + RES_QUOTA, 0); if (error) goto out_ipres; error = skeleton_call(ip, er, private); if (error) goto out_end_trans; error = gfs2_meta_inode_buffer(ip, &dibh); if (!error) { if (er->er_flags & GFS2_ERF_MODE) { gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), (ip->i_inode.i_mode & S_IFMT) == (er->er_mode & S_IFMT)); ip->i_inode.i_mode = er->er_mode; } 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); }out_end_trans: gfs2_trans_end(GFS2_SB(&ip->i_inode));out_ipres: gfs2_inplace_release(ip);out_gunlock_q: gfs2_quota_unlock(ip);out: gfs2_alloc_put(ip); return error;}static int ea_init_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, void *private){ struct buffer_head *bh; int error; error = ea_alloc_blk(ip, &bh); if (error) return error; ip->i_di.di_eattr = bh->b_blocknr; error = ea_write(ip, GFS2_EA_BH2FIRST(bh), er); brelse(bh); return error;}/** * ea_init - initializes a new eattr block * @ip: * @er: * * Returns: errno */static int ea_init(struct gfs2_inode *ip, struct gfs2_ea_request *er){ unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize; unsigned int blks = 1; if (GFS2_EAREQ_SIZE_STUFFED(er) > jbsize) blks += DIV_ROUND_UP(er->er_data_len, jbsize); return ea_alloc_skeleton(ip, er, blks, ea_init_i, NULL);}static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea){ u32 ea_size = GFS2_EA_SIZE(ea); struct gfs2_ea_header *new = (struct gfs2_ea_header *)((char *)ea + ea_size); u32 new_size = GFS2_EA_REC_LEN(ea) - ea_size; int last = ea->ea_flags & GFS2_EAFLAG_LAST; ea->ea_rec_len = cpu_to_be32(ea_size); ea->ea_flags ^= last; new->ea_rec_len = cpu_to_be32(new_size); new->ea_flags = last; return new;}static void ea_set_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; u32 len; gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1); if (!prev || !GFS2_EA_IS_STUFFED(ea)) { ea->ea_type = GFS2_EATYPE_UNUSED; return; } else if (GFS2_EA2NEXT(prev) != ea) { prev = GFS2_EA2NEXT(prev); gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), GFS2_EA2NEXT(prev) == ea); } 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;}struct ea_set { int ea_split; struct gfs2_ea_request *es_er; struct gfs2_ea_location *es_el; struct buffer_head *es_bh; struct gfs2_ea_header *es_ea;};static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh, struct gfs2_ea_header *ea, struct ea_set *es){ struct gfs2_ea_request *er = es->es_er; struct buffer_head *dibh; int error; error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + 2 * RES_EATTR, 0); if (error) return error; gfs2_trans_add_bh(ip->i_gl, bh, 1); if (es->ea_split) ea = ea_split_ea(ea); ea_write(ip, ea, er); if (es->es_el) ea_set_remove_stuffed(ip, es->es_el); error = gfs2_meta_inode_buffer(ip, &dibh); if (error) goto out; if (er->er_flags & GFS2_ERF_MODE) { gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), (ip->i_inode.i_mode & S_IFMT) == (er->er_mode & S_IFMT)); ip->i_inode.i_mode = er->er_mode; } 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);out: gfs2_trans_end(GFS2_SB(&ip->i_inode)); return error;}static int ea_set_simple_alloc(struct gfs2_inode *ip, struct gfs2_ea_request *er, void *private){ struct ea_set *es = private; struct gfs2_ea_header *ea = es->es_ea; int error; gfs2_trans_add_bh(ip->i_gl, es->es_bh, 1); if (es->ea_split) ea = ea_split_ea(ea); error = ea_write(ip, ea, er); if (error) return error; if (es->es_el) ea_set_remove_stuffed(ip, es->es_el); return 0;}static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh, struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, void *private){ struct ea_set *es = private; unsigned int size; int stuffed; int error; stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er, &size); if (ea->ea_type == GFS2_EATYPE_UNUSED) { if (GFS2_EA_REC_LEN(ea) < size) return 0; if (!GFS2_EA_IS_STUFFED(ea)) { error = ea_remove_unstuffed(ip, bh, ea, prev, 1); if (error) return error; } es->ea_split = 0; } else if (GFS2_EA_REC_LEN(ea) - GFS2_EA_SIZE(ea) >= size) es->ea_split = 1; else return 0; if (stuffed) { error = ea_set_simple_noalloc(ip, bh, ea, es); if (error) return error; } else { unsigned int blks; es->es_bh = bh; es->es_ea = ea; blks = 2 + DIV_ROUND_UP(es->es_er->er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize); error = ea_alloc_skeleton(ip, es->es_er, blks, ea_set_simple_alloc, es); if (error) return error; } return 1;}static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er, void *private){ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct buffer_head *indbh, *newbh; __be64 *eablk; int error; int mh_size = sizeof(struct gfs2_meta_header); if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) { __be64 *end; 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 + mh_size); end = eablk + sdp->sd_inptrs; for (; eablk < end; eablk++) if (!*eablk) break; if (eablk == end) { error = -ENOSPC; goto out; } gfs2_trans_add_bh(ip->i_gl, indbh, 1); } else { u64 blk; blk = gfs2_alloc_meta(ip); indbh = gfs2_meta_new(ip->i_gl, blk); gfs2_trans_add_bh(ip->i_gl, indbh, 1); gfs2_metatype_set(indbh, GFS2_METATYPE_IN, GFS2_FORMAT_IN); gfs2_buffer_clear_tail(indbh, mh_size); eablk = (__be64 *)(indbh->b_data + mh_size); *eablk = cpu_to_be64(ip->i_di.di_eattr); ip->i_di.di_eattr = blk; ip->i_di.di_flags |= GFS2_DIF_EA_INDIRECT; ip->i_di.di_blocks++; gfs2_set_inode_blocks(&ip->i_inode); eablk++; } error = ea_alloc_blk(ip, &newbh); if (error) goto out; *eablk = cpu_to_be64((u64)newbh->b_blocknr); error = ea_write(ip, GFS2_EA_BH2FIRST(newbh), er); brelse(newbh); if (error) goto out; if (private) ea_set_remove_stuffed(ip, private);out: brelse(indbh); return error;}static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er, struct gfs2_ea_location *el)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -