1 /* 2 * Copyright (C) 2014 Filipe David Borba Manana <fdmanana@gmail.com> 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public 6 * License v2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public 14 * License along with this program; if not, write to the 15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 16 * Boston, MA 021110-1307, USA. 17 */ 18 19 #include <linux/hashtable.h> 20 #include "props.h" 21 #include "btrfs_inode.h" 22 #include "hash.h" 23 #include "transaction.h" 24 #include "xattr.h" 25 26 #define BTRFS_PROP_HANDLERS_HT_BITS 8 27 static DEFINE_HASHTABLE(prop_handlers_ht, BTRFS_PROP_HANDLERS_HT_BITS); 28 29 struct prop_handler { 30 struct hlist_node node; 31 const char *xattr_name; 32 int (*validate)(const char *value, size_t len); 33 int (*apply)(struct inode *inode, const char *value, size_t len); 34 const char *(*extract)(struct inode *inode); 35 int inheritable; 36 }; 37 38 static int prop_compression_validate(const char *value, size_t len); 39 static int prop_compression_apply(struct inode *inode, 40 const char *value, 41 size_t len); 42 static const char *prop_compression_extract(struct inode *inode); 43 44 static struct prop_handler prop_handlers[] = { 45 { 46 .xattr_name = XATTR_BTRFS_PREFIX "compression", 47 .validate = prop_compression_validate, 48 .apply = prop_compression_apply, 49 .extract = prop_compression_extract, 50 .inheritable = 1 51 }, 52 }; 53 54 void __init btrfs_props_init(void) 55 { 56 int i; 57 58 hash_init(prop_handlers_ht); 59 60 for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) { 61 struct prop_handler *p = &prop_handlers[i]; 62 u64 h = btrfs_name_hash(p->xattr_name, strlen(p->xattr_name)); 63 64 hash_add(prop_handlers_ht, &p->node, h); 65 } 66 } 67 68 static const struct hlist_head *find_prop_handlers_by_hash(const u64 hash) 69 { 70 struct hlist_head *h; 71 72 h = &prop_handlers_ht[hash_min(hash, BTRFS_PROP_HANDLERS_HT_BITS)]; 73 if (hlist_empty(h)) 74 return NULL; 75 76 return h; 77 } 78 79 static const struct prop_handler * 80 find_prop_handler(const char *name, 81 const struct hlist_head *handlers) 82 { 83 struct prop_handler *h; 84 85 if (!handlers) { 86 u64 hash = btrfs_name_hash(name, strlen(name)); 87 88 handlers = find_prop_handlers_by_hash(hash); 89 if (!handlers) 90 return NULL; 91 } 92 93 hlist_for_each_entry(h, handlers, node) 94 if (!strcmp(h->xattr_name, name)) 95 return h; 96 97 return NULL; 98 } 99 100 static int __btrfs_set_prop(struct btrfs_trans_handle *trans, 101 struct inode *inode, 102 const char *name, 103 const char *value, 104 size_t value_len, 105 int flags) 106 { 107 const struct prop_handler *handler; 108 int ret; 109 110 if (strlen(name) <= XATTR_BTRFS_PREFIX_LEN) 111 return -EINVAL; 112 113 handler = find_prop_handler(name, NULL); 114 if (!handler) 115 return -EINVAL; 116 117 if (value_len == 0) { 118 ret = __btrfs_setxattr(trans, inode, handler->xattr_name, 119 NULL, 0, flags); 120 if (ret) 121 return ret; 122 123 ret = handler->apply(inode, NULL, 0); 124 ASSERT(ret == 0); 125 126 return ret; 127 } 128 129 ret = handler->validate(value, value_len); 130 if (ret) 131 return ret; 132 ret = __btrfs_setxattr(trans, inode, handler->xattr_name, 133 value, value_len, flags); 134 if (ret) 135 return ret; 136 ret = handler->apply(inode, value, value_len); 137 if (ret) { 138 __btrfs_setxattr(trans, inode, handler->xattr_name, 139 NULL, 0, flags); 140 return ret; 141 } 142 143 set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags); 144 145 return 0; 146 } 147 148 int btrfs_set_prop(struct inode *inode, 149 const char *name, 150 const char *value, 151 size_t value_len, 152 int flags) 153 { 154 return __btrfs_set_prop(NULL, inode, name, value, value_len, flags); 155 } 156 157 static int iterate_object_props(struct btrfs_root *root, 158 struct btrfs_path *path, 159 u64 objectid, 160 void (*iterator)(void *, 161 const struct prop_handler *, 162 const char *, 163 size_t), 164 void *ctx) 165 { 166 int ret; 167 char *name_buf = NULL; 168 char *value_buf = NULL; 169 int name_buf_len = 0; 170 int value_buf_len = 0; 171 172 while (1) { 173 struct btrfs_key key; 174 struct btrfs_dir_item *di; 175 struct extent_buffer *leaf; 176 u32 total_len, cur, this_len; 177 int slot; 178 const struct hlist_head *handlers; 179 180 slot = path->slots[0]; 181 leaf = path->nodes[0]; 182 183 if (slot >= btrfs_header_nritems(leaf)) { 184 ret = btrfs_next_leaf(root, path); 185 if (ret < 0) 186 goto out; 187 else if (ret > 0) 188 break; 189 continue; 190 } 191 192 btrfs_item_key_to_cpu(leaf, &key, slot); 193 if (key.objectid != objectid) 194 break; 195 if (key.type != BTRFS_XATTR_ITEM_KEY) 196 break; 197 198 handlers = find_prop_handlers_by_hash(key.offset); 199 if (!handlers) 200 goto next_slot; 201 202 di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); 203 cur = 0; 204 total_len = btrfs_item_size_nr(leaf, slot); 205 206 while (cur < total_len) { 207 u32 name_len = btrfs_dir_name_len(leaf, di); 208 u32 data_len = btrfs_dir_data_len(leaf, di); 209 unsigned long name_ptr, data_ptr; 210 const struct prop_handler *handler; 211 212 this_len = sizeof(*di) + name_len + data_len; 213 name_ptr = (unsigned long)(di + 1); 214 data_ptr = name_ptr + name_len; 215 216 if (name_len <= XATTR_BTRFS_PREFIX_LEN || 217 memcmp_extent_buffer(leaf, XATTR_BTRFS_PREFIX, 218 name_ptr, 219 XATTR_BTRFS_PREFIX_LEN)) 220 goto next_dir_item; 221 222 if (name_len >= name_buf_len) { 223 kfree(name_buf); 224 name_buf_len = name_len + 1; 225 name_buf = kmalloc(name_buf_len, GFP_NOFS); 226 if (!name_buf) { 227 ret = -ENOMEM; 228 goto out; 229 } 230 } 231 read_extent_buffer(leaf, name_buf, name_ptr, name_len); 232 name_buf[name_len] = '\0'; 233 234 handler = find_prop_handler(name_buf, handlers); 235 if (!handler) 236 goto next_dir_item; 237 238 if (data_len > value_buf_len) { 239 kfree(value_buf); 240 value_buf_len = data_len; 241 value_buf = kmalloc(data_len, GFP_NOFS); 242 if (!value_buf) { 243 ret = -ENOMEM; 244 goto out; 245 } 246 } 247 read_extent_buffer(leaf, value_buf, data_ptr, data_len); 248 249 iterator(ctx, handler, value_buf, data_len); 250 next_dir_item: 251 cur += this_len; 252 di = (struct btrfs_dir_item *)((char *) di + this_len); 253 } 254 255 next_slot: 256 path->slots[0]++; 257 } 258 259 ret = 0; 260 out: 261 btrfs_release_path(path); 262 kfree(name_buf); 263 kfree(value_buf); 264 265 return ret; 266 } 267 268 static void inode_prop_iterator(void *ctx, 269 const struct prop_handler *handler, 270 const char *value, 271 size_t len) 272 { 273 struct inode *inode = ctx; 274 struct btrfs_root *root = BTRFS_I(inode)->root; 275 int ret; 276 277 ret = handler->apply(inode, value, len); 278 if (unlikely(ret)) 279 btrfs_warn(root->fs_info, 280 "error applying prop %s to ino %llu (root %llu): %d", 281 handler->xattr_name, btrfs_ino(inode), 282 root->root_key.objectid, ret); 283 else 284 set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags); 285 } 286 287 int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path) 288 { 289 struct btrfs_root *root = BTRFS_I(inode)->root; 290 u64 ino = btrfs_ino(inode); 291 int ret; 292 293 ret = iterate_object_props(root, path, ino, inode_prop_iterator, inode); 294 295 return ret; 296 } 297 298 static int inherit_props(struct btrfs_trans_handle *trans, 299 struct inode *inode, 300 struct inode *parent) 301 { 302 struct btrfs_root *root = BTRFS_I(inode)->root; 303 int ret; 304 int i; 305 306 if (!test_bit(BTRFS_INODE_HAS_PROPS, 307 &BTRFS_I(parent)->runtime_flags)) 308 return 0; 309 310 for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) { 311 const struct prop_handler *h = &prop_handlers[i]; 312 const char *value; 313 u64 num_bytes; 314 315 if (!h->inheritable) 316 continue; 317 318 value = h->extract(parent); 319 if (!value) 320 continue; 321 322 num_bytes = btrfs_calc_trans_metadata_size(root, 1); 323 ret = btrfs_block_rsv_add(root, trans->block_rsv, 324 num_bytes, BTRFS_RESERVE_NO_FLUSH); 325 if (ret) 326 goto out; 327 ret = __btrfs_set_prop(trans, inode, h->xattr_name, 328 value, strlen(value), 0); 329 btrfs_block_rsv_release(root, trans->block_rsv, num_bytes); 330 if (ret) 331 goto out; 332 } 333 ret = 0; 334 out: 335 return ret; 336 } 337 338 int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans, 339 struct inode *inode, 340 struct inode *dir) 341 { 342 if (!dir) 343 return 0; 344 345 return inherit_props(trans, inode, dir); 346 } 347 348 int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans, 349 struct btrfs_root *root, 350 struct btrfs_root *parent_root) 351 { 352 struct btrfs_key key; 353 struct inode *parent_inode, *child_inode; 354 int ret; 355 356 key.objectid = BTRFS_FIRST_FREE_OBJECTID; 357 key.type = BTRFS_INODE_ITEM_KEY; 358 key.offset = 0; 359 360 parent_inode = btrfs_iget(parent_root->fs_info->sb, &key, 361 parent_root, NULL); 362 if (IS_ERR(parent_inode)) 363 return PTR_ERR(parent_inode); 364 365 child_inode = btrfs_iget(root->fs_info->sb, &key, root, NULL); 366 if (IS_ERR(child_inode)) { 367 iput(parent_inode); 368 return PTR_ERR(child_inode); 369 } 370 371 ret = inherit_props(trans, child_inode, parent_inode); 372 iput(child_inode); 373 iput(parent_inode); 374 375 return ret; 376 } 377 378 static int prop_compression_validate(const char *value, size_t len) 379 { 380 if (!strncmp("lzo", value, len)) 381 return 0; 382 else if (!strncmp("zlib", value, len)) 383 return 0; 384 385 return -EINVAL; 386 } 387 388 static int prop_compression_apply(struct inode *inode, 389 const char *value, 390 size_t len) 391 { 392 int type; 393 394 if (len == 0) { 395 BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS; 396 BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS; 397 BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE; 398 399 return 0; 400 } 401 402 if (!strncmp("lzo", value, len)) 403 type = BTRFS_COMPRESS_LZO; 404 else if (!strncmp("zlib", value, len)) 405 type = BTRFS_COMPRESS_ZLIB; 406 else 407 return -EINVAL; 408 409 BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS; 410 BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS; 411 BTRFS_I(inode)->force_compress = type; 412 413 return 0; 414 } 415 416 static const char *prop_compression_extract(struct inode *inode) 417 { 418 switch (BTRFS_I(inode)->force_compress) { 419 case BTRFS_COMPRESS_ZLIB: 420 return "zlib"; 421 case BTRFS_COMPRESS_LZO: 422 return "lzo"; 423 } 424 425 return NULL; 426 } 427 428 429