.. | .. |
---|
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"); |
---|