Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'for-5.18-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux

Pull btrfs fixes from David Sterba:
"A few more fixes mostly around how some file attributes could be set.

- fix handling of compression property:
- don't allow setting it on anything else than regular file or
directory
- do not allow setting it on nodatacow files via properties

- improved error handling when setting xattr

- make sure symlinks are always properly logged"

* tag 'for-5.18-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
btrfs: skip compression property for anything other than files and dirs
btrfs: do not BUG_ON() on failure to update inode when setting xattr
btrfs: always log symlinks in full mode
btrfs: do not allow compression on nodatacow files
btrfs: export a helper for compression hard check

+91 -23
+11
fs/btrfs/btrfs_inode.h
··· 384 384 return ret; 385 385 } 386 386 387 + /* 388 + * Check if the inode has flags compatible with compression 389 + */ 390 + static inline bool btrfs_inode_can_compress(const struct btrfs_inode *inode) 391 + { 392 + if (inode->flags & BTRFS_INODE_NODATACOW || 393 + inode->flags & BTRFS_INODE_NODATASUM) 394 + return false; 395 + return true; 396 + } 397 + 387 398 struct btrfs_dio_private { 388 399 struct inode *inode; 389 400
+2 -13
fs/btrfs/inode.c
··· 481 481 } 482 482 483 483 /* 484 - * Check if the inode has flags compatible with compression 485 - */ 486 - static inline bool inode_can_compress(struct btrfs_inode *inode) 487 - { 488 - if (inode->flags & BTRFS_INODE_NODATACOW || 489 - inode->flags & BTRFS_INODE_NODATASUM) 490 - return false; 491 - return true; 492 - } 493 - 494 - /* 495 484 * Check if the inode needs to be submitted to compression, based on mount 496 485 * options, defragmentation, properties or heuristics. 497 486 */ ··· 489 500 { 490 501 struct btrfs_fs_info *fs_info = inode->root->fs_info; 491 502 492 - if (!inode_can_compress(inode)) { 503 + if (!btrfs_inode_can_compress(inode)) { 493 504 WARN(IS_ENABLED(CONFIG_BTRFS_DEBUG), 494 505 KERN_ERR "BTRFS: unexpected compression for ino %llu\n", 495 506 btrfs_ino(inode)); ··· 2008 2019 ASSERT(!zoned || btrfs_is_data_reloc_root(inode->root)); 2009 2020 ret = run_delalloc_nocow(inode, locked_page, start, end, 2010 2021 page_started, nr_written); 2011 - } else if (!inode_can_compress(inode) || 2022 + } else if (!btrfs_inode_can_compress(inode) || 2012 2023 !inode_need_compress(inode, start, end)) { 2013 2024 if (zoned) 2014 2025 ret = run_delalloc_zoned(inode, locked_page, start, end,
+54 -5
fs/btrfs/props.c
··· 17 17 struct prop_handler { 18 18 struct hlist_node node; 19 19 const char *xattr_name; 20 - int (*validate)(const char *value, size_t len); 20 + int (*validate)(const struct btrfs_inode *inode, const char *value, 21 + size_t len); 21 22 int (*apply)(struct inode *inode, const char *value, size_t len); 22 23 const char *(*extract)(struct inode *inode); 24 + bool (*ignore)(const struct btrfs_inode *inode); 23 25 int inheritable; 24 26 }; 25 27 ··· 57 55 return NULL; 58 56 } 59 57 60 - int btrfs_validate_prop(const char *name, const char *value, size_t value_len) 58 + int btrfs_validate_prop(const struct btrfs_inode *inode, const char *name, 59 + const char *value, size_t value_len) 61 60 { 62 61 const struct prop_handler *handler; 63 62 ··· 72 69 if (value_len == 0) 73 70 return 0; 74 71 75 - return handler->validate(value, value_len); 72 + return handler->validate(inode, value, value_len); 73 + } 74 + 75 + /* 76 + * Check if a property should be ignored (not set) for an inode. 77 + * 78 + * @inode: The target inode. 79 + * @name: The property's name. 80 + * 81 + * The caller must be sure the given property name is valid, for example by 82 + * having previously called btrfs_validate_prop(). 83 + * 84 + * Returns: true if the property should be ignored for the given inode 85 + * false if the property must not be ignored for the given inode 86 + */ 87 + bool btrfs_ignore_prop(const struct btrfs_inode *inode, const char *name) 88 + { 89 + const struct prop_handler *handler; 90 + 91 + handler = find_prop_handler(name, NULL); 92 + ASSERT(handler != NULL); 93 + 94 + return handler->ignore(inode); 76 95 } 77 96 78 97 int btrfs_set_prop(struct btrfs_trans_handle *trans, struct inode *inode, ··· 277 252 return ret; 278 253 } 279 254 280 - static int prop_compression_validate(const char *value, size_t len) 255 + static int prop_compression_validate(const struct btrfs_inode *inode, 256 + const char *value, size_t len) 281 257 { 258 + if (!btrfs_inode_can_compress(inode)) 259 + return -EINVAL; 260 + 282 261 if (!value) 283 262 return 0; 284 263 ··· 339 310 return 0; 340 311 } 341 312 313 + static bool prop_compression_ignore(const struct btrfs_inode *inode) 314 + { 315 + /* 316 + * Compression only has effect for regular files, and for directories 317 + * we set it just to propagate it to new files created inside them. 318 + * Everything else (symlinks, devices, sockets, fifos) is pointless as 319 + * it will do nothing, so don't waste metadata space on a compression 320 + * xattr for anything that is neither a file nor a directory. 321 + */ 322 + if (!S_ISREG(inode->vfs_inode.i_mode) && 323 + !S_ISDIR(inode->vfs_inode.i_mode)) 324 + return true; 325 + 326 + return false; 327 + } 328 + 342 329 static const char *prop_compression_extract(struct inode *inode) 343 330 { 344 331 switch (BTRFS_I(inode)->prop_compress) { ··· 375 330 .validate = prop_compression_validate, 376 331 .apply = prop_compression_apply, 377 332 .extract = prop_compression_extract, 333 + .ignore = prop_compression_ignore, 378 334 .inheritable = 1 379 335 }, 380 336 }; ··· 402 356 if (!h->inheritable) 403 357 continue; 404 358 359 + if (h->ignore(BTRFS_I(inode))) 360 + continue; 361 + 405 362 value = h->extract(parent); 406 363 if (!value) 407 364 continue; ··· 413 364 * This is not strictly necessary as the property should be 414 365 * valid, but in case it isn't, don't propagate it further. 415 366 */ 416 - ret = h->validate(value, strlen(value)); 367 + ret = h->validate(BTRFS_I(inode), value, strlen(value)); 417 368 if (ret) 418 369 continue; 419 370
+3 -1
fs/btrfs/props.h
··· 13 13 int btrfs_set_prop(struct btrfs_trans_handle *trans, struct inode *inode, 14 14 const char *name, const char *value, size_t value_len, 15 15 int flags); 16 - int btrfs_validate_prop(const char *name, const char *value, size_t value_len); 16 + int btrfs_validate_prop(const struct btrfs_inode *inode, const char *name, 17 + const char *value, size_t value_len); 18 + bool btrfs_ignore_prop(const struct btrfs_inode *inode, const char *name); 17 19 18 20 int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path); 19 21
+13 -1
fs/btrfs/tree-log.c
··· 5805 5805 } 5806 5806 5807 5807 /* 5808 + * For symlinks, we must always log their content, which is stored in an 5809 + * inline extent, otherwise we could end up with an empty symlink after 5810 + * log replay, which is invalid on linux (symlink(2) returns -ENOENT if 5811 + * one attempts to create an empty symlink). 5812 + * We don't need to worry about flushing delalloc, because when we create 5813 + * the inline extent when the symlink is created (we never have delalloc 5814 + * for symlinks). 5815 + */ 5816 + if (S_ISLNK(inode->vfs_inode.i_mode)) 5817 + inode_only = LOG_INODE_ALL; 5818 + 5819 + /* 5808 5820 * Before logging the inode item, cache the value returned by 5809 5821 * inode_logged(), because after that we have the need to figure out if 5810 5822 * the inode was previously logged in this transaction. ··· 6194 6182 } 6195 6183 6196 6184 ctx->log_new_dentries = false; 6197 - if (type == BTRFS_FT_DIR || type == BTRFS_FT_SYMLINK) 6185 + if (type == BTRFS_FT_DIR) 6198 6186 log_mode = LOG_INODE_ALL; 6199 6187 ret = btrfs_log_inode(trans, BTRFS_I(di_inode), 6200 6188 log_mode, ctx);
+8 -3
fs/btrfs/xattr.c
··· 262 262 inode_inc_iversion(inode); 263 263 inode->i_ctime = current_time(inode); 264 264 ret = btrfs_update_inode(trans, root, BTRFS_I(inode)); 265 - BUG_ON(ret); 265 + if (ret) 266 + btrfs_abort_transaction(trans, ret); 266 267 out: 267 268 if (start_trans) 268 269 btrfs_end_transaction(trans); ··· 404 403 struct btrfs_root *root = BTRFS_I(inode)->root; 405 404 406 405 name = xattr_full_name(handler, name); 407 - ret = btrfs_validate_prop(name, value, size); 406 + ret = btrfs_validate_prop(BTRFS_I(inode), name, value, size); 408 407 if (ret) 409 408 return ret; 409 + 410 + if (btrfs_ignore_prop(BTRFS_I(inode), name)) 411 + return 0; 410 412 411 413 trans = btrfs_start_transaction(root, 2); 412 414 if (IS_ERR(trans)) ··· 420 416 inode_inc_iversion(inode); 421 417 inode->i_ctime = current_time(inode); 422 418 ret = btrfs_update_inode(trans, root, BTRFS_I(inode)); 423 - BUG_ON(ret); 419 + if (ret) 420 + btrfs_abort_transaction(trans, ret); 424 421 } 425 422 426 423 btrfs_end_transaction(trans);