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 .xattr_name = NULL 54 } 55 }; 56 57 void __init btrfs_props_init(void) 58 { 59 struct prop_handler *p; 60 61 hash_init(prop_handlers_ht); 62 63 for (p = &prop_handlers[0]; p->xattr_name; p++) { 64 u64 h = btrfs_name_hash(p->xattr_name, strlen(p->xattr_name)); 65 66 hash_add(prop_handlers_ht, &p->node, h); 67 } 68 } 69 70 static const struct hlist_head *find_prop_handlers_by_hash(const u64 hash) 71 { 72 struct hlist_head *h; 73 74 h = &prop_handlers_ht[hash_min(hash, BTRFS_PROP_HANDLERS_HT_BITS)]; 75 if (hlist_empty(h)) 76 return NULL; 77 78 return h; 79 } 80 81 static const struct prop_handler * 82 find_prop_handler(const char *name, 83 const struct hlist_head *handlers) 84 { 85 struct prop_handler *h; 86 87 if (!handlers) { 88 u64 hash = btrfs_name_hash(name, strlen(name)); 89 90 handlers = find_prop_handlers_by_hash(hash); 91 if (!handlers) 92 return NULL; 93 } 94 95 hlist_for_each_entry(h, handlers, node) 96 if (!strcmp(h->xattr_name, name)) 97 return h; 98 99 return NULL; 100 } 101 102 static int __btrfs_set_prop(struct btrfs_trans_handle *trans, 103 struct inode *inode, 104 const char *name, 105 const char *value, 106 size_t value_len, 107 int flags) 108 { 109 const struct prop_handler *handler; 110 int ret; 111 112 if (strlen(name) <= XATTR_BTRFS_PREFIX_LEN) 113 return -EINVAL; 114 115 handler = find_prop_handler(name, NULL); 116 if (!handler) 117 return -EINVAL; 118 119 if (value_len == 0) { 120 ret = __btrfs_setxattr(trans, inode, handler->xattr_name, 121 NULL, 0, flags); 122 if (ret) 123 return ret; 124 125 ret = handler->apply(inode, NULL, 0); 126 ASSERT(ret == 0); 127 128 return ret; 129 } 130 131 ret = handler->validate(value, value_len); 132 if (ret) 133 return ret; 134 ret = __btrfs_setxattr(trans, inode, handler->xattr_name, 135 value, value_len, flags); 136 if (ret) 137 return ret; 138 ret = handler->apply(inode, value, value_len); 139 if (ret) { 140 __btrfs_setxattr(trans, inode, handler->xattr_name, 141 NULL, 0, flags); 142 return ret; 143 } 144 145 set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags); 146 147 return 0; 148 } 149 150 int btrfs_set_prop(struct inode *inode, 151 const char *name, 152 const char *value, 153 size_t value_len, 154 int flags) 155 { 156 return __btrfs_set_prop(NULL, inode, name, value, value_len, flags); 157 } 158 159 static int iterate_object_props(struct btrfs_root *root, 160 struct btrfs_path *path, 161 u64 objectid, 162 void (*iterator)(void *, 163 const struct prop_handler *, 164 const char *, 165 size_t), 166 void *ctx) 167 { 168 int ret; 169 char *name_buf = NULL; 170 char *value_buf = NULL; 171 int name_buf_len = 0; 172 int value_buf_len = 0; 173 174 while (1) { 175 struct btrfs_key key; 176 struct btrfs_dir_item *di; 177 struct extent_buffer *leaf; 178 u32 total_len, cur, this_len; 179 int slot; 180 const struct hlist_head *handlers; 181 182 slot = path->slots[0]; 183 leaf = path->nodes[0]; 184 185 if (slot >= btrfs_header_nritems(leaf)) { 186 ret = btrfs_next_leaf(root, path); 187 if (ret < 0) 188 goto out; 189 else if (ret > 0) 190 break; 191 continue; 192 } 193 194 btrfs_item_key_to_cpu(leaf, &key, slot); 195 if (key.objectid != objectid) 196 break; 197 if (key.type != BTRFS_XATTR_ITEM_KEY) 198 break; 199 200 handlers = find_prop_handlers_by_hash(key.offset); 201 if (!handlers) 202 goto next_slot; 203 204 di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); 205 cur = 0; 206 total_len = btrfs_item_size_nr(leaf, slot); 207 208 while (cur < total_len) { 209 u32 name_len = btrfs_dir_name_len(leaf, di); 210 u32 data_len = btrfs_dir_data_len(leaf, di); 211 unsigned long name_ptr, data_ptr; 212 const struct prop_handler *handler; 213 214 this_len = sizeof(*di) + name_len + data_len; 215 name_ptr = (unsigned long)(di + 1); 216 data_ptr = name_ptr + name_len; 217 218 if (name_len <= XATTR_BTRFS_PREFIX_LEN || 219 memcmp_extent_buffer(leaf, XATTR_BTRFS_PREFIX, 220 name_ptr, 221 XATTR_BTRFS_PREFIX_LEN)) 222 goto next_dir_item; 223 224 if (name_len >= name_buf_len) { 225 kfree(name_buf); 226 name_buf_len = name_len + 1; 227 name_buf = kmalloc(name_buf_len, GFP_NOFS); 228 if (!name_buf) { 229 ret = -ENOMEM; 230 goto out; 231 } 232 } 233 read_extent_buffer(leaf, name_buf, name_ptr, name_len); 234 name_buf[name_len] = '\0'; 235 236 handler = find_prop_handler(name_buf, handlers); 237 if (!handler) 238 goto next_dir_item; 239 240 if (data_len > value_buf_len) { 241 kfree(value_buf); 242 value_buf_len = data_len; 243 value_buf = kmalloc(data_len, GFP_NOFS); 244 if (!value_buf) { 245 ret = -ENOMEM; 246 goto out; 247 } 248 } 249 read_extent_buffer(leaf, value_buf, data_ptr, data_len); 250 251 iterator(ctx, handler, value_buf, data_len); 252 next_dir_item: 253 cur += this_len; 254 di = (struct btrfs_dir_item *)((char *) di + this_len); 255 } 256 257 next_slot: 258 path->slots[0]++; 259 } 260 261 ret = 0; 262 out: 263 btrfs_release_path(path); 264 kfree(name_buf); 265 kfree(value_buf); 266 267 return ret; 268 } 269 270 static void inode_prop_iterator(void *ctx, 271 const struct prop_handler *handler, 272 const char *value, 273 size_t len) 274 { 275 struct inode *inode = ctx; 276 struct btrfs_root *root = BTRFS_I(inode)->root; 277 int ret; 278 279 ret = handler->apply(inode, value, len); 280 if (unlikely(ret)) 281 btrfs_warn(root->fs_info, 282 "error applying prop %s to ino %llu (root %llu): %d", 283 handler->xattr_name, btrfs_ino(inode), 284 root->root_key.objectid, ret); 285 else 286 set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags); 287 } 288 289 int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path) 290 { 291 struct btrfs_root *root = BTRFS_I(inode)->root; 292 u64 ino = btrfs_ino(inode); 293 int ret; 294 295 ret = iterate_object_props(root, path, ino, inode_prop_iterator, inode); 296 297 return ret; 298 } 299 300 static int inherit_props(struct btrfs_trans_handle *trans, 301 struct inode *inode, 302 struct inode *parent) 303 { 304 const struct prop_handler *h; 305 struct btrfs_root *root = BTRFS_I(inode)->root; 306 int ret; 307 308 if (!test_bit(BTRFS_INODE_HAS_PROPS, 309 &BTRFS_I(parent)->runtime_flags)) 310 return 0; 311 312 for (h = &prop_handlers[0]; h->xattr_name; h++) { 313 const char *value; 314 u64 num_bytes; 315 316 if (!h->inheritable) 317 continue; 318 319 value = h->extract(parent); 320 if (!value) 321 continue; 322 323 num_bytes = btrfs_calc_trans_metadata_size(root, 1); 324 ret = btrfs_block_rsv_add(root, trans->block_rsv, 325 num_bytes, BTRFS_RESERVE_NO_FLUSH); 326 if (ret) 327 goto out; 328 ret = __btrfs_set_prop(trans, inode, h->xattr_name, 329 value, strlen(value), 0); 330 btrfs_block_rsv_release(root, trans->block_rsv, num_bytes); 331 if (ret) 332 goto out; 333 } 334 ret = 0; 335 out: 336 return ret; 337 } 338 339 int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans, 340 struct inode *inode, 341 struct inode *dir) 342 { 343 if (!dir) 344 return 0; 345 346 return inherit_props(trans, inode, dir); 347 } 348 349 int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans, 350 struct btrfs_root *root, 351 struct btrfs_root *parent_root) 352 { 353 struct btrfs_key key; 354 struct inode *parent_inode, *child_inode; 355 int ret; 356 357 key.objectid = BTRFS_FIRST_FREE_OBJECTID; 358 key.type = BTRFS_INODE_ITEM_KEY; 359 key.offset = 0; 360 361 parent_inode = btrfs_iget(parent_root->fs_info->sb, &key, 362 parent_root, NULL); 363 if (IS_ERR(parent_inode)) 364 return PTR_ERR(parent_inode); 365 366 child_inode = btrfs_iget(root->fs_info->sb, &key, root, NULL); 367 if (IS_ERR(child_inode)) { 368 iput(parent_inode); 369 return PTR_ERR(child_inode); 370 } 371 372 ret = inherit_props(trans, child_inode, parent_inode); 373 iput(child_inode); 374 iput(parent_inode); 375 376 return ret; 377 } 378 379 static int prop_compression_validate(const char *value, size_t len) 380 { 381 if (!strncmp("lzo", value, len)) 382 return 0; 383 else if (!strncmp("zlib", value, len)) 384 return 0; 385 386 return -EINVAL; 387 } 388 389 static int prop_compression_apply(struct inode *inode, 390 const char *value, 391 size_t len) 392 { 393 int type; 394 395 if (len == 0) { 396 BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS; 397 BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS; 398 BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE; 399 400 return 0; 401 } 402 403 if (!strncmp("lzo", value, len)) 404 type = BTRFS_COMPRESS_LZO; 405 else if (!strncmp("zlib", value, len)) 406 type = BTRFS_COMPRESS_ZLIB; 407 else 408 return -EINVAL; 409 410 BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS; 411 BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS; 412 BTRFS_I(inode)->force_compress = type; 413 414 return 0; 415 } 416 417 static const char *prop_compression_extract(struct inode *inode) 418 { 419 switch (BTRFS_I(inode)->force_compress) { 420 case BTRFS_COMPRESS_ZLIB: 421 return "zlib"; 422 case BTRFS_COMPRESS_LZO: 423 return "lzo"; 424 } 425 426 return NULL; 427 } 428