1 /** 2 * xattr.c 3 * 4 * Many parts of codes are copied from Linux kernel/fs/f2fs. 5 * 6 * Copyright (C) 2015 Huawei Ltd. 7 * Witten by: 8 * Hou Pengyang <houpengyang (at) huawei.com> 9 * Liu Shuoran <liushuoran (at) huawei.com> 10 * Jaegeuk Kim <jaegeuk (at) kernel.org> 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License version 2 as 14 * published by the Free Software Foundation. 15 */ 16 #include "fsck.h" 17 #include "node.h" 18 #include "xattr.h" 19 20 #define XATTR_CREATE 0x1 21 #define XATTR_REPLACE 0x2 22 23 static void *read_all_xattrs(struct f2fs_sb_info *sbi, struct f2fs_node *inode) 24 { 25 struct f2fs_xattr_header *header; 26 void *txattr_addr; 27 u64 inline_size = inline_xattr_size(&inode->i); 28 29 txattr_addr = calloc(inline_size + BLOCK_SZ, 1); 30 ASSERT(txattr_addr); 31 32 if (inline_size) 33 memcpy(txattr_addr, inline_xattr_addr(&inode->i), inline_size); 34 35 /* Read from xattr node block. */ 36 if (inode->i.i_xattr_nid) { 37 struct node_info ni; 38 int ret; 39 40 get_node_info(sbi, le32_to_cpu(inode->i.i_xattr_nid), &ni); 41 ret = dev_read_block(txattr_addr + inline_size, ni.blk_addr); 42 ASSERT(ret >= 0); 43 } 44 45 header = XATTR_HDR(txattr_addr); 46 47 /* Never been allocated xattrs */ 48 if (le32_to_cpu(header->h_magic) != F2FS_XATTR_MAGIC) { 49 header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC); 50 header->h_refcount = cpu_to_le32(1); 51 } 52 return txattr_addr; 53 } 54 55 static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index, 56 size_t len, const char *name) 57 { 58 struct f2fs_xattr_entry *entry; 59 list_for_each_xattr(entry, base_addr) { 60 if (entry->e_name_index != index) 61 continue; 62 if (entry->e_name_len != len) 63 continue; 64 if (!memcmp(entry->e_name, name, len)) 65 break; 66 } 67 return entry; 68 } 69 70 static void write_all_xattrs(struct f2fs_sb_info *sbi, 71 struct f2fs_node *inode, __u32 hsize, void *txattr_addr) 72 { 73 void *xattr_addr; 74 struct dnode_of_data dn; 75 struct node_info ni; 76 struct f2fs_node *xattr_node; 77 nid_t new_nid = 0; 78 block_t blkaddr; 79 nid_t xnid = le32_to_cpu(inode->i.i_xattr_nid); 80 u64 inline_size = inline_xattr_size(&inode->i); 81 int ret; 82 83 ASSERT(inode->i.i_inline & F2FS_INLINE_XATTR); 84 memcpy(inline_xattr_addr(&inode->i), txattr_addr, inline_size); 85 86 if (hsize <= inline_size) 87 return; 88 89 if (!xnid) { 90 f2fs_alloc_nid(sbi, &new_nid, 0); 91 92 set_new_dnode(&dn, inode, NULL, new_nid); 93 /* NAT entry would be updated by new_node_page. */ 94 blkaddr = new_node_block(sbi, &dn, XATTR_NODE_OFFSET); 95 ASSERT(dn.node_blk); 96 xattr_node = dn.node_blk; 97 inode->i.i_xattr_nid = cpu_to_le32(new_nid); 98 } else { 99 set_new_dnode(&dn, inode, NULL, xnid); 100 get_node_info(sbi, xnid, &ni); 101 blkaddr = ni.blk_addr; 102 xattr_node = calloc(BLOCK_SZ, 1); 103 ASSERT(xattr_node); 104 ret = dev_read_block(xattr_node, ni.blk_addr); 105 ASSERT(ret >= 0); 106 } 107 108 /* write to xattr node block */ 109 xattr_addr = (void *)xattr_node; 110 memcpy(xattr_addr, txattr_addr + inline_size, 111 PAGE_SIZE - sizeof(struct node_footer)); 112 113 ret = dev_write_block(xattr_node, blkaddr); 114 ASSERT(ret >= 0); 115 } 116 117 int f2fs_setxattr(struct f2fs_sb_info *sbi, nid_t ino, int index, const char *name, 118 const void *value, size_t size, int flags) 119 { 120 struct f2fs_node *inode; 121 void *base_addr; 122 struct f2fs_xattr_entry *here, *last; 123 struct node_info ni; 124 int error = 0; 125 int len; 126 int found, newsize; 127 __u32 new_hsize; 128 int ret; 129 130 if (name == NULL) 131 return -EINVAL; 132 133 if (value == NULL) 134 return -EINVAL; 135 136 len = strlen(name); 137 138 if (len > F2FS_NAME_LEN || size > MAX_VALUE_LEN) 139 return -ERANGE; 140 141 if (ino < 3) 142 return -EINVAL; 143 144 /* Now We just support selinux */ 145 ASSERT(index == F2FS_XATTR_INDEX_SECURITY); 146 147 get_node_info(sbi, ino, &ni); 148 inode = calloc(BLOCK_SZ, 1); 149 ASSERT(inode); 150 ret = dev_read_block(inode, ni.blk_addr); 151 ASSERT(ret >= 0); 152 153 base_addr = read_all_xattrs(sbi, inode); 154 ASSERT(base_addr); 155 156 here = __find_xattr(base_addr, index, len, name); 157 158 found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1; 159 160 if ((flags & XATTR_REPLACE) && !found) { 161 error = -ENODATA; 162 goto exit; 163 } else if ((flags & XATTR_CREATE) && found) { 164 error = -EEXIST; 165 goto exit; 166 } 167 168 last = here; 169 while (!IS_XATTR_LAST_ENTRY(last)) 170 last = XATTR_NEXT_ENTRY(last); 171 172 newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size); 173 174 /* 1. Check space */ 175 if (value) { 176 int free; 177 /* 178 * If value is NULL, it is remove operation. 179 * In case of update operation, we calculate free. 180 */ 181 free = MIN_OFFSET - ((char *)last - (char *)base_addr); 182 if (found) 183 free = free + ENTRY_SIZE(here); 184 if (free < newsize) { 185 error = -ENOSPC; 186 goto exit; 187 } 188 } 189 190 /* 2. Remove old entry */ 191 if (found) { 192 /* 193 * If entry if sound, remove old entry. 194 * If not found, remove operation is not needed 195 */ 196 struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here); 197 int oldsize = ENTRY_SIZE(here); 198 199 memmove(here, next, (char *)last - (char *)next); 200 last = (struct f2fs_xattr_entry *)((char *)last - oldsize); 201 memset(last, 0, oldsize); 202 203 } 204 205 new_hsize = (char *)last - (char *)base_addr; 206 207 /* 3. Write new entry */ 208 if (value) { 209 char *pval; 210 /* 211 * Before we come here, old entry is removed. 212 * We just write new entry. 213 */ 214 memset(last, 0, newsize); 215 last->e_name_index = index; 216 last->e_name_len = len; 217 memcpy(last->e_name, name, len); 218 pval = last->e_name + len; 219 memcpy(pval, value, size); 220 last->e_value_size = cpu_to_le16(size); 221 new_hsize += newsize; 222 } 223 224 write_all_xattrs(sbi, inode, new_hsize, base_addr); 225 226 /* inode need update */ 227 ret = dev_write_block(inode, ni.blk_addr); 228 ASSERT(ret >= 0); 229 exit: 230 free(base_addr); 231 return error; 232 } 233 234 int inode_set_selinux(struct f2fs_sb_info *sbi, u32 ino, const char *secon) 235 { 236 if (!secon) 237 return 0; 238 239 return f2fs_setxattr(sbi, ino, F2FS_XATTR_INDEX_SECURITY, 240 XATTR_SELINUX_SUFFIX, secon, strlen(secon), 1); 241 } 242