| .. | .. |
|---|
| 135 | 135 | return handler; |
|---|
| 136 | 136 | } |
|---|
| 137 | 137 | |
|---|
| 138 | +static bool |
|---|
| 139 | +ext2_xattr_header_valid(struct ext2_xattr_header *header) |
|---|
| 140 | +{ |
|---|
| 141 | + if (header->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || |
|---|
| 142 | + header->h_blocks != cpu_to_le32(1)) |
|---|
| 143 | + return false; |
|---|
| 144 | + |
|---|
| 145 | + return true; |
|---|
| 146 | +} |
|---|
| 147 | + |
|---|
| 148 | +static bool |
|---|
| 149 | +ext2_xattr_entry_valid(struct ext2_xattr_entry *entry, |
|---|
| 150 | + char *end, size_t end_offs) |
|---|
| 151 | +{ |
|---|
| 152 | + struct ext2_xattr_entry *next; |
|---|
| 153 | + size_t size; |
|---|
| 154 | + |
|---|
| 155 | + next = EXT2_XATTR_NEXT(entry); |
|---|
| 156 | + if ((char *)next >= end) |
|---|
| 157 | + return false; |
|---|
| 158 | + |
|---|
| 159 | + if (entry->e_value_block != 0) |
|---|
| 160 | + return false; |
|---|
| 161 | + |
|---|
| 162 | + size = le32_to_cpu(entry->e_value_size); |
|---|
| 163 | + if (size > end_offs || |
|---|
| 164 | + le16_to_cpu(entry->e_value_offs) + size > end_offs) |
|---|
| 165 | + return false; |
|---|
| 166 | + |
|---|
| 167 | + return true; |
|---|
| 168 | +} |
|---|
| 169 | + |
|---|
| 170 | +static int |
|---|
| 171 | +ext2_xattr_cmp_entry(int name_index, size_t name_len, const char *name, |
|---|
| 172 | + struct ext2_xattr_entry *entry) |
|---|
| 173 | +{ |
|---|
| 174 | + int cmp; |
|---|
| 175 | + |
|---|
| 176 | + cmp = name_index - entry->e_name_index; |
|---|
| 177 | + if (!cmp) |
|---|
| 178 | + cmp = name_len - entry->e_name_len; |
|---|
| 179 | + if (!cmp) |
|---|
| 180 | + cmp = memcmp(name, entry->e_name, name_len); |
|---|
| 181 | + |
|---|
| 182 | + return cmp; |
|---|
| 183 | +} |
|---|
| 184 | + |
|---|
| 138 | 185 | /* |
|---|
| 139 | 186 | * ext2_xattr_get() |
|---|
| 140 | 187 | * |
|---|
| .. | .. |
|---|
| 153 | 200 | struct ext2_xattr_entry *entry; |
|---|
| 154 | 201 | size_t name_len, size; |
|---|
| 155 | 202 | char *end; |
|---|
| 156 | | - int error; |
|---|
| 203 | + int error, not_found; |
|---|
| 157 | 204 | struct mb_cache *ea_block_cache = EA_BLOCK_CACHE(inode); |
|---|
| 158 | 205 | |
|---|
| 159 | 206 | ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", |
|---|
| .. | .. |
|---|
| 177 | 224 | ea_bdebug(bh, "b_count=%d, refcount=%d", |
|---|
| 178 | 225 | atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); |
|---|
| 179 | 226 | end = bh->b_data + bh->b_size; |
|---|
| 180 | | - if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || |
|---|
| 181 | | - HDR(bh)->h_blocks != cpu_to_le32(1)) { |
|---|
| 182 | | -bad_block: ext2_error(inode->i_sb, "ext2_xattr_get", |
|---|
| 227 | + if (!ext2_xattr_header_valid(HDR(bh))) { |
|---|
| 228 | +bad_block: |
|---|
| 229 | + ext2_error(inode->i_sb, "ext2_xattr_get", |
|---|
| 183 | 230 | "inode %ld: bad block %d", inode->i_ino, |
|---|
| 184 | 231 | EXT2_I(inode)->i_file_acl); |
|---|
| 185 | 232 | error = -EIO; |
|---|
| .. | .. |
|---|
| 189 | 236 | /* find named attribute */ |
|---|
| 190 | 237 | entry = FIRST_ENTRY(bh); |
|---|
| 191 | 238 | while (!IS_LAST_ENTRY(entry)) { |
|---|
| 192 | | - struct ext2_xattr_entry *next = |
|---|
| 193 | | - EXT2_XATTR_NEXT(entry); |
|---|
| 194 | | - if ((char *)next >= end) |
|---|
| 239 | + if (!ext2_xattr_entry_valid(entry, end, |
|---|
| 240 | + inode->i_sb->s_blocksize)) |
|---|
| 195 | 241 | goto bad_block; |
|---|
| 196 | | - if (name_index == entry->e_name_index && |
|---|
| 197 | | - name_len == entry->e_name_len && |
|---|
| 198 | | - memcmp(name, entry->e_name, name_len) == 0) |
|---|
| 242 | + |
|---|
| 243 | + not_found = ext2_xattr_cmp_entry(name_index, name_len, name, |
|---|
| 244 | + entry); |
|---|
| 245 | + if (!not_found) |
|---|
| 199 | 246 | goto found; |
|---|
| 200 | | - entry = next; |
|---|
| 247 | + if (not_found < 0) |
|---|
| 248 | + break; |
|---|
| 249 | + |
|---|
| 250 | + entry = EXT2_XATTR_NEXT(entry); |
|---|
| 201 | 251 | } |
|---|
| 202 | 252 | if (ext2_xattr_cache_insert(ea_block_cache, bh)) |
|---|
| 203 | 253 | ea_idebug(inode, "cache insert failed"); |
|---|
| 204 | 254 | error = -ENODATA; |
|---|
| 205 | 255 | goto cleanup; |
|---|
| 206 | 256 | found: |
|---|
| 207 | | - /* check the buffer size */ |
|---|
| 208 | | - if (entry->e_value_block != 0) |
|---|
| 209 | | - goto bad_block; |
|---|
| 210 | 257 | size = le32_to_cpu(entry->e_value_size); |
|---|
| 211 | | - if (size > inode->i_sb->s_blocksize || |
|---|
| 212 | | - le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize) |
|---|
| 213 | | - goto bad_block; |
|---|
| 214 | | - |
|---|
| 215 | 258 | if (ext2_xattr_cache_insert(ea_block_cache, bh)) |
|---|
| 216 | 259 | ea_idebug(inode, "cache insert failed"); |
|---|
| 217 | 260 | if (buffer) { |
|---|
| .. | .. |
|---|
| 267 | 310 | ea_bdebug(bh, "b_count=%d, refcount=%d", |
|---|
| 268 | 311 | atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); |
|---|
| 269 | 312 | end = bh->b_data + bh->b_size; |
|---|
| 270 | | - if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || |
|---|
| 271 | | - HDR(bh)->h_blocks != cpu_to_le32(1)) { |
|---|
| 272 | | -bad_block: ext2_error(inode->i_sb, "ext2_xattr_list", |
|---|
| 313 | + if (!ext2_xattr_header_valid(HDR(bh))) { |
|---|
| 314 | +bad_block: |
|---|
| 315 | + ext2_error(inode->i_sb, "ext2_xattr_list", |
|---|
| 273 | 316 | "inode %ld: bad block %d", inode->i_ino, |
|---|
| 274 | 317 | EXT2_I(inode)->i_file_acl); |
|---|
| 275 | 318 | error = -EIO; |
|---|
| .. | .. |
|---|
| 279 | 322 | /* check the on-disk data structure */ |
|---|
| 280 | 323 | entry = FIRST_ENTRY(bh); |
|---|
| 281 | 324 | while (!IS_LAST_ENTRY(entry)) { |
|---|
| 282 | | - struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(entry); |
|---|
| 283 | | - |
|---|
| 284 | | - if ((char *)next >= end) |
|---|
| 325 | + if (!ext2_xattr_entry_valid(entry, end, |
|---|
| 326 | + inode->i_sb->s_blocksize)) |
|---|
| 285 | 327 | goto bad_block; |
|---|
| 286 | | - entry = next; |
|---|
| 328 | + entry = EXT2_XATTR_NEXT(entry); |
|---|
| 287 | 329 | } |
|---|
| 288 | 330 | if (ext2_xattr_cache_insert(ea_block_cache, bh)) |
|---|
| 289 | 331 | ea_idebug(inode, "cache insert failed"); |
|---|
| .. | .. |
|---|
| 343 | 385 | return; |
|---|
| 344 | 386 | |
|---|
| 345 | 387 | spin_lock(&EXT2_SB(sb)->s_lock); |
|---|
| 388 | + ext2_update_dynamic_rev(sb); |
|---|
| 346 | 389 | EXT2_SET_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR); |
|---|
| 347 | 390 | spin_unlock(&EXT2_SB(sb)->s_lock); |
|---|
| 348 | 391 | mark_buffer_dirty(EXT2_SB(sb)->s_sbh); |
|---|
| .. | .. |
|---|
| 367 | 410 | struct super_block *sb = inode->i_sb; |
|---|
| 368 | 411 | struct buffer_head *bh = NULL; |
|---|
| 369 | 412 | struct ext2_xattr_header *header = NULL; |
|---|
| 370 | | - struct ext2_xattr_entry *here, *last; |
|---|
| 413 | + struct ext2_xattr_entry *here = NULL, *last = NULL; |
|---|
| 371 | 414 | size_t name_len, free, min_offs = sb->s_blocksize; |
|---|
| 372 | 415 | int not_found = 1, error; |
|---|
| 373 | 416 | char *end; |
|---|
| .. | .. |
|---|
| 394 | 437 | name_len = strlen(name); |
|---|
| 395 | 438 | if (name_len > 255 || value_len > sb->s_blocksize) |
|---|
| 396 | 439 | return -ERANGE; |
|---|
| 440 | + error = dquot_initialize(inode); |
|---|
| 441 | + if (error) |
|---|
| 442 | + return error; |
|---|
| 397 | 443 | down_write(&EXT2_I(inode)->xattr_sem); |
|---|
| 398 | 444 | if (EXT2_I(inode)->i_file_acl) { |
|---|
| 399 | 445 | /* The inode already has an extended attribute block. */ |
|---|
| .. | .. |
|---|
| 406 | 452 | le32_to_cpu(HDR(bh)->h_refcount)); |
|---|
| 407 | 453 | header = HDR(bh); |
|---|
| 408 | 454 | end = bh->b_data + bh->b_size; |
|---|
| 409 | | - if (header->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || |
|---|
| 410 | | - header->h_blocks != cpu_to_le32(1)) { |
|---|
| 411 | | -bad_block: ext2_error(sb, "ext2_xattr_set", |
|---|
| 455 | + if (!ext2_xattr_header_valid(header)) { |
|---|
| 456 | +bad_block: |
|---|
| 457 | + ext2_error(sb, "ext2_xattr_set", |
|---|
| 412 | 458 | "inode %ld: bad block %d", inode->i_ino, |
|---|
| 413 | 459 | EXT2_I(inode)->i_file_acl); |
|---|
| 414 | 460 | error = -EIO; |
|---|
| 415 | 461 | goto cleanup; |
|---|
| 416 | 462 | } |
|---|
| 417 | | - /* Find the named attribute. */ |
|---|
| 418 | | - here = FIRST_ENTRY(bh); |
|---|
| 419 | | - while (!IS_LAST_ENTRY(here)) { |
|---|
| 420 | | - struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(here); |
|---|
| 421 | | - if ((char *)next >= end) |
|---|
| 422 | | - goto bad_block; |
|---|
| 423 | | - if (!here->e_value_block && here->e_value_size) { |
|---|
| 424 | | - size_t offs = le16_to_cpu(here->e_value_offs); |
|---|
| 425 | | - if (offs < min_offs) |
|---|
| 426 | | - min_offs = offs; |
|---|
| 427 | | - } |
|---|
| 428 | | - not_found = name_index - here->e_name_index; |
|---|
| 429 | | - if (!not_found) |
|---|
| 430 | | - not_found = name_len - here->e_name_len; |
|---|
| 431 | | - if (!not_found) |
|---|
| 432 | | - not_found = memcmp(name, here->e_name,name_len); |
|---|
| 433 | | - if (not_found <= 0) |
|---|
| 434 | | - break; |
|---|
| 435 | | - here = next; |
|---|
| 436 | | - } |
|---|
| 437 | | - last = here; |
|---|
| 438 | | - /* We still need to compute min_offs and last. */ |
|---|
| 463 | + /* |
|---|
| 464 | + * Find the named attribute. If not found, 'here' will point |
|---|
| 465 | + * to entry where the new attribute should be inserted to |
|---|
| 466 | + * maintain sorting. |
|---|
| 467 | + */ |
|---|
| 468 | + last = FIRST_ENTRY(bh); |
|---|
| 439 | 469 | while (!IS_LAST_ENTRY(last)) { |
|---|
| 440 | | - struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(last); |
|---|
| 441 | | - if ((char *)next >= end) |
|---|
| 470 | + if (!ext2_xattr_entry_valid(last, end, sb->s_blocksize)) |
|---|
| 442 | 471 | goto bad_block; |
|---|
| 443 | | - if (!last->e_value_block && last->e_value_size) { |
|---|
| 472 | + if (last->e_value_size) { |
|---|
| 444 | 473 | size_t offs = le16_to_cpu(last->e_value_offs); |
|---|
| 445 | 474 | if (offs < min_offs) |
|---|
| 446 | 475 | min_offs = offs; |
|---|
| 447 | 476 | } |
|---|
| 448 | | - last = next; |
|---|
| 477 | + if (not_found > 0) { |
|---|
| 478 | + not_found = ext2_xattr_cmp_entry(name_index, |
|---|
| 479 | + name_len, |
|---|
| 480 | + name, last); |
|---|
| 481 | + if (not_found <= 0) |
|---|
| 482 | + here = last; |
|---|
| 483 | + } |
|---|
| 484 | + last = EXT2_XATTR_NEXT(last); |
|---|
| 449 | 485 | } |
|---|
| 486 | + if (not_found > 0) |
|---|
| 487 | + here = last; |
|---|
| 450 | 488 | |
|---|
| 451 | 489 | /* Check whether we have enough space left. */ |
|---|
| 452 | 490 | free = min_offs - ((char*)last - (char*)header) - sizeof(__u32); |
|---|
| .. | .. |
|---|
| 454 | 492 | /* We will use a new extended attribute block. */ |
|---|
| 455 | 493 | free = sb->s_blocksize - |
|---|
| 456 | 494 | sizeof(struct ext2_xattr_header) - sizeof(__u32); |
|---|
| 457 | | - here = last = NULL; /* avoid gcc uninitialized warning. */ |
|---|
| 458 | 495 | } |
|---|
| 459 | 496 | |
|---|
| 460 | 497 | if (not_found) { |
|---|
| .. | .. |
|---|
| 470 | 507 | error = -EEXIST; |
|---|
| 471 | 508 | if (flags & XATTR_CREATE) |
|---|
| 472 | 509 | goto cleanup; |
|---|
| 473 | | - if (!here->e_value_block && here->e_value_size) { |
|---|
| 474 | | - size_t size = le32_to_cpu(here->e_value_size); |
|---|
| 475 | | - |
|---|
| 476 | | - if (le16_to_cpu(here->e_value_offs) + size > |
|---|
| 477 | | - sb->s_blocksize || size > sb->s_blocksize) |
|---|
| 478 | | - goto bad_block; |
|---|
| 479 | | - free += EXT2_XATTR_SIZE(size); |
|---|
| 480 | | - } |
|---|
| 510 | + free += EXT2_XATTR_SIZE(le32_to_cpu(here->e_value_size)); |
|---|
| 481 | 511 | free += EXT2_XATTR_LEN(name_len); |
|---|
| 482 | 512 | } |
|---|
| 483 | 513 | error = -ENOSPC; |
|---|
| .. | .. |
|---|
| 506 | 536 | |
|---|
| 507 | 537 | unlock_buffer(bh); |
|---|
| 508 | 538 | ea_bdebug(bh, "cloning"); |
|---|
| 509 | | - header = kmalloc(bh->b_size, GFP_KERNEL); |
|---|
| 539 | + header = kmemdup(HDR(bh), bh->b_size, GFP_KERNEL); |
|---|
| 510 | 540 | error = -ENOMEM; |
|---|
| 511 | 541 | if (header == NULL) |
|---|
| 512 | 542 | goto cleanup; |
|---|
| 513 | | - memcpy(header, HDR(bh), bh->b_size); |
|---|
| 514 | 543 | header->h_refcount = cpu_to_le32(1); |
|---|
| 515 | 544 | |
|---|
| 516 | 545 | offset = (char *)here - bh->b_data; |
|---|
| .. | .. |
|---|
| 542 | 571 | here->e_name_len = name_len; |
|---|
| 543 | 572 | memcpy(here->e_name, name, name_len); |
|---|
| 544 | 573 | } else { |
|---|
| 545 | | - if (!here->e_value_block && here->e_value_size) { |
|---|
| 574 | + if (here->e_value_size) { |
|---|
| 546 | 575 | char *first_val = (char *)header + min_offs; |
|---|
| 547 | 576 | size_t offs = le16_to_cpu(here->e_value_offs); |
|---|
| 548 | 577 | char *val = (char *)header + offs; |
|---|
| .. | .. |
|---|
| 562 | 591 | /* Remove the old value. */ |
|---|
| 563 | 592 | memmove(first_val + size, first_val, val - first_val); |
|---|
| 564 | 593 | memset(first_val, 0, size); |
|---|
| 565 | | - here->e_value_offs = 0; |
|---|
| 566 | 594 | min_offs += size; |
|---|
| 567 | 595 | |
|---|
| 568 | 596 | /* Adjust all value offsets. */ |
|---|
| 569 | 597 | last = ENTRY(header+1); |
|---|
| 570 | 598 | while (!IS_LAST_ENTRY(last)) { |
|---|
| 571 | 599 | size_t o = le16_to_cpu(last->e_value_offs); |
|---|
| 572 | | - if (!last->e_value_block && o < offs) |
|---|
| 600 | + if (o < offs) |
|---|
| 573 | 601 | last->e_value_offs = |
|---|
| 574 | 602 | cpu_to_le16(o + size); |
|---|
| 575 | 603 | last = EXT2_XATTR_NEXT(last); |
|---|
| 576 | 604 | } |
|---|
| 605 | + |
|---|
| 606 | + here->e_value_offs = 0; |
|---|
| 577 | 607 | } |
|---|
| 578 | 608 | if (value == NULL) { |
|---|
| 579 | 609 | /* Remove the old name. */ |
|---|
| .. | .. |
|---|
| 664 | 694 | /* We need to allocate a new block */ |
|---|
| 665 | 695 | ext2_fsblk_t goal = ext2_group_first_block_no(sb, |
|---|
| 666 | 696 | EXT2_I(inode)->i_block_group); |
|---|
| 667 | | - int block = ext2_new_block(inode, goal, &error); |
|---|
| 697 | + ext2_fsblk_t block = ext2_new_block(inode, goal, &error); |
|---|
| 668 | 698 | if (error) |
|---|
| 669 | 699 | goto cleanup; |
|---|
| 670 | | - ea_idebug(inode, "creating block %d", block); |
|---|
| 700 | + ea_idebug(inode, "creating block %lu", block); |
|---|
| 671 | 701 | |
|---|
| 672 | 702 | new_bh = sb_getblk(sb, block); |
|---|
| 673 | 703 | if (unlikely(!new_bh)) { |
|---|
| .. | .. |
|---|
| 765 | 795 | struct buffer_head *bh = NULL; |
|---|
| 766 | 796 | struct ext2_sb_info *sbi = EXT2_SB(inode->i_sb); |
|---|
| 767 | 797 | |
|---|
| 768 | | - down_write(&EXT2_I(inode)->xattr_sem); |
|---|
| 798 | + /* |
|---|
| 799 | + * We are the only ones holding inode reference. The xattr_sem should |
|---|
| 800 | + * better be unlocked! We could as well just not acquire xattr_sem at |
|---|
| 801 | + * all but this makes the code more futureproof. OTOH we need trylock |
|---|
| 802 | + * here to avoid false-positive warning from lockdep about reclaim |
|---|
| 803 | + * circular dependency. |
|---|
| 804 | + */ |
|---|
| 805 | + if (WARN_ON_ONCE(!down_write_trylock(&EXT2_I(inode)->xattr_sem))) |
|---|
| 806 | + return; |
|---|
| 769 | 807 | if (!EXT2_I(inode)->i_file_acl) |
|---|
| 770 | 808 | goto cleanup; |
|---|
| 771 | 809 | |
|---|
| 772 | | - if (!ext2_data_block_valid(sbi, EXT2_I(inode)->i_file_acl, 0)) { |
|---|
| 810 | + if (!ext2_data_block_valid(sbi, EXT2_I(inode)->i_file_acl, 1)) { |
|---|
| 773 | 811 | ext2_error(inode->i_sb, "ext2_xattr_delete_inode", |
|---|
| 774 | 812 | "inode %ld: xattr block %d is out of data blocks range", |
|---|
| 775 | 813 | inode->i_ino, EXT2_I(inode)->i_file_acl); |
|---|
| .. | .. |
|---|
| 784 | 822 | goto cleanup; |
|---|
| 785 | 823 | } |
|---|
| 786 | 824 | ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count))); |
|---|
| 787 | | - if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || |
|---|
| 788 | | - HDR(bh)->h_blocks != cpu_to_le32(1)) { |
|---|
| 825 | + if (!ext2_xattr_header_valid(HDR(bh))) { |
|---|
| 789 | 826 | ext2_error(inode->i_sb, "ext2_xattr_delete_inode", |
|---|
| 790 | 827 | "inode %ld: bad block %d", inode->i_ino, |
|---|
| 791 | 828 | EXT2_I(inode)->i_file_acl); |
|---|
| .. | .. |
|---|
| 836 | 873 | __u32 hash = le32_to_cpu(HDR(bh)->h_hash); |
|---|
| 837 | 874 | int error; |
|---|
| 838 | 875 | |
|---|
| 839 | | - error = mb_cache_entry_create(cache, GFP_NOFS, hash, bh->b_blocknr, 1); |
|---|
| 876 | + error = mb_cache_entry_create(cache, GFP_NOFS, hash, bh->b_blocknr, |
|---|
| 877 | + true); |
|---|
| 840 | 878 | if (error) { |
|---|
| 841 | 879 | if (error == -EBUSY) { |
|---|
| 842 | 880 | ea_bdebug(bh, "already in cache"); |
|---|