📄 xattr.c
字号:
} else if (ji->ea.flag & DXD_INLINE) { if (min_size <= sizeof (ji->i_inline_ea)) { ea_buf->flag = EA_INLINE; ea_buf->max_size = sizeof (ji->i_inline_ea); ea_buf->xattr = (struct jfs_ea_list *) ji->i_inline_ea; goto size_check; } current_blocks = 0; } else { if (!(ji->ea.flag & DXD_EXTENT)) { jfs_error(sb, "ea_get: invalid ea.flag)"); return -EIO; } current_blocks = (ea_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; } size = max(min_size, ea_size); if (size > PSIZE) { /* * To keep the rest of the code simple. Allocate a * contiguous buffer to work with */ ea_buf->xattr = kmalloc(size, GFP_KERNEL); if (ea_buf->xattr == NULL) return -ENOMEM; ea_buf->flag = EA_MALLOC; ea_buf->max_size = (size + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1); if (ea_size == 0) return 0; if ((rc = ea_read(inode, ea_buf->xattr))) { kfree(ea_buf->xattr); ea_buf->xattr = NULL; return rc; } goto size_check; } blocks_needed = (min_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; if (blocks_needed > current_blocks) { rc = dbAlloc(inode, INOHINT(inode), (s64) blocks_needed, &blkno); if (rc) return rc; DXDlength(&ea_buf->new_ea, blocks_needed); DXDaddress(&ea_buf->new_ea, blkno); ea_buf->new_ea.flag = DXD_EXTENT; DXDsize(&ea_buf->new_ea, min_size); ea_buf->flag = EA_EXTENT | EA_NEW; ea_buf->mp = get_metapage(inode, blkno, blocks_needed << sb->s_blocksize_bits, 1); if (ea_buf->mp == NULL) { dbFree(inode, blkno, (s64) blocks_needed); return -EIO; } ea_buf->xattr = ea_buf->mp->data; ea_buf->max_size = (min_size + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1); if (ea_size == 0) return 0; if ((rc = ea_read(inode, ea_buf->xattr))) { discard_metapage(ea_buf->mp); dbFree(inode, blkno, (s64) blocks_needed); return rc; } goto size_check; } ea_buf->flag = EA_EXTENT; ea_buf->mp = read_metapage(inode, addressDXD(&ji->ea), lengthDXD(&ji->ea) << sb->s_blocksize_bits, 1); if (ea_buf->mp == NULL) return -EIO; ea_buf->xattr = ea_buf->mp->data; ea_buf->max_size = (ea_size + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1); size_check: if (EALIST_SIZE(ea_buf->xattr) != ea_size) { printk(KERN_ERR "ea_get: invalid extended attribute\n"); dump_mem("xattr", ea_buf->xattr, ea_size); ea_release(inode, ea_buf); return -EIO; } return ea_size;}static void ea_release(struct inode *inode, struct ea_buffer *ea_buf){ if (ea_buf->flag & EA_MALLOC) kfree(ea_buf->xattr); else if (ea_buf->flag & EA_EXTENT) { assert(ea_buf->mp); release_metapage(ea_buf->mp); if (ea_buf->flag & EA_NEW) dbFree(inode, addressDXD(&ea_buf->new_ea), lengthDXD(&ea_buf->new_ea)); }}static int ea_put(struct inode *inode, struct ea_buffer *ea_buf, int new_size){ struct jfs_inode_info *ji = JFS_IP(inode); unsigned long old_blocks, new_blocks; int rc = 0; tid_t tid; if (new_size == 0) { ea_release(inode, ea_buf); ea_buf = 0; } else if (ea_buf->flag & EA_INLINE) { assert(new_size <= sizeof (ji->i_inline_ea)); ji->mode2 &= ~INLINEEA; ea_buf->new_ea.flag = DXD_INLINE; DXDsize(&ea_buf->new_ea, new_size); DXDaddress(&ea_buf->new_ea, 0); DXDlength(&ea_buf->new_ea, 0); } else if (ea_buf->flag & EA_MALLOC) { rc = ea_write(inode, ea_buf->xattr, new_size, &ea_buf->new_ea); kfree(ea_buf->xattr); } else if (ea_buf->flag & EA_NEW) { /* We have already allocated a new dxd */ flush_metapage(ea_buf->mp); } else { /* ->xattr must point to original ea's metapage */ rc = ea_write(inode, ea_buf->xattr, new_size, &ea_buf->new_ea); discard_metapage(ea_buf->mp); } if (rc) return rc; tid = txBegin(inode->i_sb, 0); down(&ji->commit_sem); old_blocks = new_blocks = 0; if (ji->ea.flag & DXD_EXTENT) { invalidate_dxd_metapages(inode, ji->ea); old_blocks = lengthDXD(&ji->ea); } if (ea_buf) { txEA(tid, inode, &ji->ea, &ea_buf->new_ea); if (ea_buf->new_ea.flag & DXD_EXTENT) { new_blocks = lengthDXD(&ea_buf->new_ea); if (ji->ea.flag & DXD_INLINE) ji->mode2 |= INLINEEA; } ji->ea = ea_buf->new_ea; } else { txEA(tid, inode, &ji->ea, 0); if (ji->ea.flag & DXD_INLINE) ji->mode2 |= INLINEEA; ji->ea.flag = 0; ji->ea.size = 0; } inode->i_blocks += LBLK2PBLK(inode->i_sb, new_blocks - old_blocks); rc = txCommit(tid, 1, &inode, 0); txEnd(tid); up(&ji->commit_sem); return rc;}static int can_set_xattr(struct inode *inode, const char *name, void *value, size_t value_len){ if (IS_RDONLY(inode)) return -EROFS; if (IS_IMMUTABLE(inode) || IS_APPEND(inode) || S_ISLNK(inode->i_mode)) return -EPERM; if((strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) != 0) && (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) != 0)) return -EOPNOTSUPP; if (!S_ISREG(inode->i_mode) && (!S_ISDIR(inode->i_mode) || inode->i_mode &S_ISVTX)) return -EPERM; return permission(inode, MAY_WRITE);}int __jfs_setxattr(struct inode *inode, const char *name, void *value, size_t value_len, int flags){ struct jfs_ea_list *ealist; struct jfs_ea *ea, *old_ea = NULL, *next_ea = NULL; struct ea_buffer ea_buf; int old_ea_size = 0; int xattr_size; int new_size; int namelen = strlen(name); char *os2name = NULL; int found = 0; int rc; int length; if ((rc = can_set_xattr(inode, name, value, value_len))) return rc; if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1, GFP_KERNEL); if (!os2name) return -ENOMEM; strcpy(os2name, name + XATTR_OS2_PREFIX_LEN); name = os2name; namelen -= XATTR_OS2_PREFIX_LEN; } xattr_size = ea_get(inode, &ea_buf, 0); if (xattr_size < 0) { rc = xattr_size; goto out; } again: ealist = (struct jfs_ea_list *) ea_buf.xattr; new_size = sizeof (struct jfs_ea_list); if (xattr_size) { for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) { if ((namelen == ea->namelen) && (memcmp(name, ea->name, namelen) == 0)) { found = 1; if (flags & XATTR_CREATE) { rc = -EEXIST; goto release; } old_ea = ea; old_ea_size = EA_SIZE(ea); next_ea = NEXT_EA(ea); } else new_size += EA_SIZE(ea); } } if (!found) { if (flags & XATTR_REPLACE) { rc = -ENODATA; goto release; } if (value == NULL) { rc = 0; goto release; } } if (value) new_size += sizeof (struct jfs_ea) + namelen + 1 + value_len; if (new_size > ea_buf.max_size) { /* * We need to allocate more space for merged ea list. * We should only have loop to again: once. */ ea_release(inode, &ea_buf); xattr_size = ea_get(inode, &ea_buf, new_size); if (xattr_size < 0) { rc = xattr_size; goto out; } goto again; } /* Remove old ea of the same name */ if (found) { /* number of bytes following target EA */ length = (char *) END_EALIST(ealist) - (char *) next_ea; if (length > 0) memmove(old_ea, next_ea, length); xattr_size -= old_ea_size; } /* Add new entry to the end */ if (value) { if (xattr_size == 0) /* Completely new ea list */ xattr_size = sizeof (struct jfs_ea_list); ea = (struct jfs_ea *) ((char *) ealist + xattr_size); ea->flag = 0; ea->namelen = namelen; ea->valuelen = (cpu_to_le16(value_len)); memcpy(ea->name, name, namelen); ea->name[namelen] = 0; if (value_len) memcpy(&ea->name[namelen + 1], value, value_len); xattr_size += EA_SIZE(ea); } /* DEBUG - If we did this right, these number match */ if (xattr_size != new_size) { printk(KERN_ERR "jfs_xsetattr: xattr_size = %d, new_size = %d\n", xattr_size, new_size); rc = -EINVAL; goto release; } /* * If we're left with an empty list, there's no ea */ if (new_size == sizeof (struct jfs_ea_list)) new_size = 0; ealist->size = cpu_to_le32(new_size); rc = ea_put(inode, &ea_buf, new_size); goto out; release: ea_release(inode, &ea_buf); out: if (os2name) kfree(os2name); return rc;}int jfs_setxattr(struct dentry *dentry, const char *name, void *value, size_t value_len, int flags){ if (value == NULL) { /* empty EA, do not remove */ value = ""; value_len = 0; } return __jfs_setxattr(dentry->d_inode, name, value, value_len, flags);}static inline int can_get_xattr(struct inode *inode, const char *name){ if(strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) == 0) return 0; return permission(inode, MAY_READ);}ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data, size_t buf_size){ struct jfs_ea_list *ealist; struct jfs_ea *ea; struct ea_buffer ea_buf; int xattr_size; ssize_t size; int namelen = strlen(name); char *os2name = NULL; int rc; char *value; if ((rc = can_get_xattr(inode, name))) return rc; if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1, GFP_KERNEL); if (!os2name) return -ENOMEM; strcpy(os2name, name + XATTR_OS2_PREFIX_LEN); name = os2name; namelen -= XATTR_OS2_PREFIX_LEN; } xattr_size = ea_get(inode, &ea_buf, 0); if (xattr_size < 0) { size = xattr_size; goto out; } if (xattr_size == 0) goto not_found; ealist = (struct jfs_ea_list *) ea_buf.xattr; /* Find the named attribute */ for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) if ((namelen == ea->namelen) && memcmp(name, ea->name, namelen) == 0) { /* Found it */ size = le16_to_cpu(ea->valuelen); if (!data) goto release; else if (size > buf_size) { size = -ERANGE; goto release; } value = ((char *) &ea->name) + ea->namelen + 1; memcpy(data, value, size); goto release; } not_found: size = -ENODATA; release: ea_release(inode, &ea_buf); out: if (os2name) kfree(os2name); return size;}ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data, size_t buf_size){ return __jfs_getxattr(dentry->d_inode, name, data, buf_size);}ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size){ struct inode *inode = dentry->d_inode; char *buffer; ssize_t size = 0; int xattr_size; struct jfs_ea_list *ealist; struct jfs_ea *ea; struct ea_buffer ea_buf; xattr_size = ea_get(inode, &ea_buf, 0); if (xattr_size < 0) { size = xattr_size; goto out; } if (xattr_size == 0) goto release; ealist = (struct jfs_ea_list *) ea_buf.xattr; /* compute required size of list */ for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) size += name_size(ea) + 1; if (!data) goto release; if (size > buf_size) { size = -ERANGE; goto release; } /* Copy attribute names to buffer */ buffer = data; for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) { int namelen = copy_name(buffer, ea); buffer += namelen + 1; } release: ea_release(inode, &ea_buf); out: return size;}int jfs_removexattr(struct dentry *dentry, const char *name){ return __jfs_setxattr(dentry->d_inode, name, 0, 0, XATTR_REPLACE);}#endif /* JFS_XATTR */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -