diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/binfmt_elf.c | 2 | ||||
| -rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 3 | ||||
| -rw-r--r-- | fs/cifs/cifs_unicode.c | 182 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.c | 2 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 23 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 3 | ||||
| -rw-r--r-- | fs/cifs/dir.c | 3 | ||||
| -rw-r--r-- | fs/cifs/file.c | 7 | ||||
| -rw-r--r-- | fs/cifs/inode.c | 31 | ||||
| -rw-r--r-- | fs/cifs/link.c | 3 | ||||
| -rw-r--r-- | fs/cifs/readdir.c | 2 | ||||
| -rw-r--r-- | fs/cifs/smb1ops.c | 3 | ||||
| -rw-r--r-- | fs/cifs/smb2pdu.c | 2 | ||||
| -rw-r--r-- | fs/omfs/bitmap.c | 2 | ||||
| -rw-r--r-- | fs/omfs/inode.c | 10 | ||||
| -rw-r--r-- | fs/overlayfs/copy_up.c | 3 | ||||
| -rw-r--r-- | fs/overlayfs/dir.c | 33 | ||||
| -rw-r--r-- | fs/overlayfs/super.c | 10 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_attr_leaf.c | 8 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_attr_leaf.h | 2 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 31 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_ialloc.c | 9 | ||||
| -rw-r--r-- | fs/xfs/xfs_attr_inactive.c | 83 | ||||
| -rw-r--r-- | fs/xfs/xfs_file.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.c | 22 | ||||
| -rw-r--r-- | fs/xfs/xfs_mount.c | 34 |
27 files changed, 351 insertions, 168 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 241ef68d2893..cd46e4158830 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
| @@ -918,7 +918,7 @@ static int load_elf_binary(struct linux_binprm *bprm) | |||
| 918 | total_size = total_mapping_size(elf_phdata, | 918 | total_size = total_mapping_size(elf_phdata, |
| 919 | loc->elf_ex.e_phnum); | 919 | loc->elf_ex.e_phnum); |
| 920 | if (!total_size) { | 920 | if (!total_size) { |
| 921 | error = -EINVAL; | 921 | retval = -EINVAL; |
| 922 | goto out_free_dentry; | 922 | goto out_free_dentry; |
| 923 | } | 923 | } |
| 924 | } | 924 | } |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 430e0348c99e..7dc886c9a78f 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include "cifsfs.h" | 24 | #include "cifsfs.h" |
| 25 | #include "dns_resolve.h" | 25 | #include "dns_resolve.h" |
| 26 | #include "cifs_debug.h" | 26 | #include "cifs_debug.h" |
| 27 | #include "cifs_unicode.h" | ||
| 27 | 28 | ||
| 28 | static LIST_HEAD(cifs_dfs_automount_list); | 29 | static LIST_HEAD(cifs_dfs_automount_list); |
| 29 | 30 | ||
| @@ -312,7 +313,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) | |||
| 312 | xid = get_xid(); | 313 | xid = get_xid(); |
| 313 | rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls, | 314 | rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls, |
| 314 | &num_referrals, &referrals, | 315 | &num_referrals, &referrals, |
| 315 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 316 | cifs_remap(cifs_sb)); |
| 316 | free_xid(xid); | 317 | free_xid(xid); |
| 317 | 318 | ||
| 318 | cifs_put_tlink(tlink); | 319 | cifs_put_tlink(tlink); |
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 0303c6793d90..5a53ac6b1e02 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c | |||
| @@ -27,41 +27,6 @@ | |||
| 27 | #include "cifsglob.h" | 27 | #include "cifsglob.h" |
| 28 | #include "cifs_debug.h" | 28 | #include "cifs_debug.h" |
| 29 | 29 | ||
| 30 | /* | ||
| 31 | * cifs_utf16_bytes - how long will a string be after conversion? | ||
| 32 | * @utf16 - pointer to input string | ||
| 33 | * @maxbytes - don't go past this many bytes of input string | ||
| 34 | * @codepage - destination codepage | ||
| 35 | * | ||
| 36 | * Walk a utf16le string and return the number of bytes that the string will | ||
| 37 | * be after being converted to the given charset, not including any null | ||
| 38 | * termination required. Don't walk past maxbytes in the source buffer. | ||
| 39 | */ | ||
| 40 | int | ||
| 41 | cifs_utf16_bytes(const __le16 *from, int maxbytes, | ||
| 42 | const struct nls_table *codepage) | ||
| 43 | { | ||
| 44 | int i; | ||
| 45 | int charlen, outlen = 0; | ||
| 46 | int maxwords = maxbytes / 2; | ||
| 47 | char tmp[NLS_MAX_CHARSET_SIZE]; | ||
| 48 | __u16 ftmp; | ||
| 49 | |||
| 50 | for (i = 0; i < maxwords; i++) { | ||
| 51 | ftmp = get_unaligned_le16(&from[i]); | ||
| 52 | if (ftmp == 0) | ||
| 53 | break; | ||
| 54 | |||
| 55 | charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE); | ||
| 56 | if (charlen > 0) | ||
| 57 | outlen += charlen; | ||
| 58 | else | ||
| 59 | outlen++; | ||
| 60 | } | ||
| 61 | |||
| 62 | return outlen; | ||
| 63 | } | ||
| 64 | |||
| 65 | int cifs_remap(struct cifs_sb_info *cifs_sb) | 30 | int cifs_remap(struct cifs_sb_info *cifs_sb) |
| 66 | { | 31 | { |
| 67 | int map_type; | 32 | int map_type; |
| @@ -155,10 +120,13 @@ convert_sfm_char(const __u16 src_char, char *target) | |||
| 155 | * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). | 120 | * enough to hold the result of the conversion (at least NLS_MAX_CHARSET_SIZE). |
| 156 | */ | 121 | */ |
| 157 | static int | 122 | static int |
| 158 | cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp, | 123 | cifs_mapchar(char *target, const __u16 *from, const struct nls_table *cp, |
| 159 | int maptype) | 124 | int maptype) |
| 160 | { | 125 | { |
| 161 | int len = 1; | 126 | int len = 1; |
| 127 | __u16 src_char; | ||
| 128 | |||
| 129 | src_char = *from; | ||
| 162 | 130 | ||
| 163 | if ((maptype == SFM_MAP_UNI_RSVD) && convert_sfm_char(src_char, target)) | 131 | if ((maptype == SFM_MAP_UNI_RSVD) && convert_sfm_char(src_char, target)) |
| 164 | return len; | 132 | return len; |
| @@ -168,10 +136,23 @@ cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp, | |||
| 168 | 136 | ||
| 169 | /* if character not one of seven in special remap set */ | 137 | /* if character not one of seven in special remap set */ |
| 170 | len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE); | 138 | len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE); |
| 171 | if (len <= 0) { | 139 | if (len <= 0) |
| 172 | *target = '?'; | 140 | goto surrogate_pair; |
| 173 | len = 1; | 141 | |
| 174 | } | 142 | return len; |
| 143 | |||
| 144 | surrogate_pair: | ||
| 145 | /* convert SURROGATE_PAIR and IVS */ | ||
| 146 | if (strcmp(cp->charset, "utf8")) | ||
| 147 | goto unknown; | ||
| 148 | len = utf16s_to_utf8s(from, 3, UTF16_LITTLE_ENDIAN, target, 6); | ||
| 149 | if (len <= 0) | ||
| 150 | goto unknown; | ||
| 151 | return len; | ||
| 152 | |||
| 153 | unknown: | ||
| 154 | *target = '?'; | ||
| 155 | len = 1; | ||
| 175 | return len; | 156 | return len; |
| 176 | } | 157 | } |
| 177 | 158 | ||
| @@ -206,7 +187,7 @@ cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, | |||
| 206 | int nullsize = nls_nullsize(codepage); | 187 | int nullsize = nls_nullsize(codepage); |
| 207 | int fromwords = fromlen / 2; | 188 | int fromwords = fromlen / 2; |
| 208 | char tmp[NLS_MAX_CHARSET_SIZE]; | 189 | char tmp[NLS_MAX_CHARSET_SIZE]; |
| 209 | __u16 ftmp; | 190 | __u16 ftmp[3]; /* ftmp[3] = 3array x 2bytes = 6bytes UTF-16 */ |
| 210 | 191 | ||
| 211 | /* | 192 | /* |
| 212 | * because the chars can be of varying widths, we need to take care | 193 | * because the chars can be of varying widths, we need to take care |
| @@ -217,9 +198,17 @@ cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, | |||
| 217 | safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); | 198 | safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize); |
| 218 | 199 | ||
| 219 | for (i = 0; i < fromwords; i++) { | 200 | for (i = 0; i < fromwords; i++) { |
| 220 | ftmp = get_unaligned_le16(&from[i]); | 201 | ftmp[0] = get_unaligned_le16(&from[i]); |
| 221 | if (ftmp == 0) | 202 | if (ftmp[0] == 0) |
| 222 | break; | 203 | break; |
| 204 | if (i + 1 < fromwords) | ||
| 205 | ftmp[1] = get_unaligned_le16(&from[i + 1]); | ||
| 206 | else | ||
| 207 | ftmp[1] = 0; | ||
| 208 | if (i + 2 < fromwords) | ||
| 209 | ftmp[2] = get_unaligned_le16(&from[i + 2]); | ||
| 210 | else | ||
| 211 | ftmp[2] = 0; | ||
| 223 | 212 | ||
| 224 | /* | 213 | /* |
| 225 | * check to see if converting this character might make the | 214 | * check to see if converting this character might make the |
| @@ -234,6 +223,17 @@ cifs_from_utf16(char *to, const __le16 *from, int tolen, int fromlen, | |||
| 234 | /* put converted char into 'to' buffer */ | 223 | /* put converted char into 'to' buffer */ |
| 235 | charlen = cifs_mapchar(&to[outlen], ftmp, codepage, map_type); | 224 | charlen = cifs_mapchar(&to[outlen], ftmp, codepage, map_type); |
| 236 | outlen += charlen; | 225 | outlen += charlen; |
| 226 | |||
| 227 | /* charlen (=bytes of UTF-8 for 1 character) | ||
| 228 | * 4bytes UTF-8(surrogate pair) is charlen=4 | ||
| 229 | * (4bytes UTF-16 code) | ||
| 230 | * 7-8bytes UTF-8(IVS) is charlen=3+4 or 4+4 | ||
| 231 | * (2 UTF-8 pairs divided to 2 UTF-16 pairs) */ | ||
| 232 | if (charlen == 4) | ||
| 233 | i++; | ||
| 234 | else if (charlen >= 5) | ||
| 235 | /* 5-6bytes UTF-8 */ | ||
| 236 | i += 2; | ||
| 237 | } | 237 | } |
| 238 | 238 | ||
| 239 | /* properly null-terminate string */ | 239 | /* properly null-terminate string */ |
| @@ -296,6 +296,46 @@ success: | |||
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | /* | 298 | /* |
| 299 | * cifs_utf16_bytes - how long will a string be after conversion? | ||
| 300 | * @utf16 - pointer to input string | ||
| 301 | * @maxbytes - don't go past this many bytes of input string | ||
| 302 | * @codepage - destination codepage | ||
| 303 | * | ||
| 304 | * Walk a utf16le string and return the number of bytes that the string will | ||
| 305 | * be after being converted to the given charset, not including any null | ||
| 306 | * termination required. Don't walk past maxbytes in the source buffer. | ||
| 307 | */ | ||
| 308 | int | ||
| 309 | cifs_utf16_bytes(const __le16 *from, int maxbytes, | ||
| 310 | const struct nls_table *codepage) | ||
| 311 | { | ||
| 312 | int i; | ||
| 313 | int charlen, outlen = 0; | ||
| 314 | int maxwords = maxbytes / 2; | ||
| 315 | char tmp[NLS_MAX_CHARSET_SIZE]; | ||
| 316 | __u16 ftmp[3]; | ||
| 317 | |||
| 318 | for (i = 0; i < maxwords; i++) { | ||
| 319 | ftmp[0] = get_unaligned_le16(&from[i]); | ||
| 320 | if (ftmp[0] == 0) | ||
| 321 | break; | ||
| 322 | if (i + 1 < maxwords) | ||
| 323 | ftmp[1] = get_unaligned_le16(&from[i + 1]); | ||
| 324 | else | ||
| 325 | ftmp[1] = 0; | ||
| 326 | if (i + 2 < maxwords) | ||
| 327 | ftmp[2] = get_unaligned_le16(&from[i + 2]); | ||
| 328 | else | ||
| 329 | ftmp[2] = 0; | ||
| 330 | |||
| 331 | charlen = cifs_mapchar(tmp, ftmp, codepage, NO_MAP_UNI_RSVD); | ||
| 332 | outlen += charlen; | ||
| 333 | } | ||
| 334 | |||
| 335 | return outlen; | ||
| 336 | } | ||
| 337 | |||
| 338 | /* | ||
| 299 | * cifs_strndup_from_utf16 - copy a string from wire format to the local | 339 | * cifs_strndup_from_utf16 - copy a string from wire format to the local |
| 300 | * codepage | 340 | * codepage |
| 301 | * @src - source string | 341 | * @src - source string |
| @@ -409,10 +449,15 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen, | |||
| 409 | char src_char; | 449 | char src_char; |
| 410 | __le16 dst_char; | 450 | __le16 dst_char; |
| 411 | wchar_t tmp; | 451 | wchar_t tmp; |
| 452 | wchar_t *wchar_to; /* UTF-16 */ | ||
| 453 | int ret; | ||
| 454 | unicode_t u; | ||
| 412 | 455 | ||
| 413 | if (map_chars == NO_MAP_UNI_RSVD) | 456 | if (map_chars == NO_MAP_UNI_RSVD) |
| 414 | return cifs_strtoUTF16(target, source, PATH_MAX, cp); | 457 | return cifs_strtoUTF16(target, source, PATH_MAX, cp); |
| 415 | 458 | ||
| 459 | wchar_to = kzalloc(6, GFP_KERNEL); | ||
| 460 | |||
| 416 | for (i = 0; i < srclen; j++) { | 461 | for (i = 0; i < srclen; j++) { |
| 417 | src_char = source[i]; | 462 | src_char = source[i]; |
| 418 | charlen = 1; | 463 | charlen = 1; |
| @@ -441,11 +486,55 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen, | |||
| 441 | * if no match, use question mark, which at least in | 486 | * if no match, use question mark, which at least in |
| 442 | * some cases serves as wild card | 487 | * some cases serves as wild card |
| 443 | */ | 488 | */ |
| 444 | if (charlen < 1) { | 489 | if (charlen > 0) |
| 445 | dst_char = cpu_to_le16(0x003f); | 490 | goto ctoUTF16; |
| 446 | charlen = 1; | 491 | |
| 492 | /* convert SURROGATE_PAIR */ | ||
| 493 | if (strcmp(cp->charset, "utf8") || !wchar_to) | ||
| 494 | goto unknown; | ||
| 495 | if (*(source + i) & 0x80) { | ||
| 496 | charlen = utf8_to_utf32(source + i, 6, &u); | ||
| 497 | if (charlen < 0) | ||
| 498 | goto unknown; | ||
| 499 | } else | ||
| 500 | goto unknown; | ||
| 501 | ret = utf8s_to_utf16s(source + i, charlen, | ||
| 502 | UTF16_LITTLE_ENDIAN, | ||
| 503 | wchar_to, 6); | ||
| 504 | if (ret < 0) | ||
| 505 | goto unknown; | ||
| 506 | |||
| 507 | i += charlen; | ||
| 508 | dst_char = cpu_to_le16(*wchar_to); | ||
| 509 | if (charlen <= 3) | ||
| 510 | /* 1-3bytes UTF-8 to 2bytes UTF-16 */ | ||
| 511 | put_unaligned(dst_char, &target[j]); | ||
| 512 | else if (charlen == 4) { | ||
| 513 | /* 4bytes UTF-8(surrogate pair) to 4bytes UTF-16 | ||
| 514 | * 7-8bytes UTF-8(IVS) divided to 2 UTF-16 | ||
| 515 | * (charlen=3+4 or 4+4) */ | ||
| 516 | put_unaligned(dst_char, &target[j]); | ||
| 517 | dst_char = cpu_to_le16(*(wchar_to + 1)); | ||
| 518 | j++; | ||
| 519 | put_unaligned(dst_char, &target[j]); | ||
| 520 | } else if (charlen >= 5) { | ||
| 521 | /* 5-6bytes UTF-8 to 6bytes UTF-16 */ | ||
| 522 | put_unaligned(dst_char, &target[j]); | ||
| 523 | dst_char = cpu_to_le16(*(wchar_to + 1)); | ||
| 524 | j++; | ||
| 525 | put_unaligned(dst_char, &target[j]); | ||
| 526 | dst_char = cpu_to_le16(*(wchar_to + 2)); | ||
| 527 | j++; | ||
| 528 | put_unaligned(dst_char, &target[j]); | ||
| 447 | } | 529 | } |
| 530 | continue; | ||
| 531 | |||
| 532 | unknown: | ||
| 533 | dst_char = cpu_to_le16(0x003f); | ||
| 534 | charlen = 1; | ||
| 448 | } | 535 | } |
| 536 | |||
| 537 | ctoUTF16: | ||
| 449 | /* | 538 | /* |
| 450 | * character may take more than one byte in the source string, | 539 | * character may take more than one byte in the source string, |
| 451 | * but will take exactly two bytes in the target string | 540 | * but will take exactly two bytes in the target string |
| @@ -456,6 +545,7 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen, | |||
| 456 | 545 | ||
| 457 | ctoUTF16_out: | 546 | ctoUTF16_out: |
| 458 | put_unaligned(0, &target[j]); /* Null terminate target unicode string */ | 547 | put_unaligned(0, &target[j]); /* Null terminate target unicode string */ |
| 548 | kfree(wchar_to); | ||
| 459 | return j; | 549 | return j; |
| 460 | } | 550 | } |
| 461 | 551 | ||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f5089bde3635..0a9fb6b53126 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -469,6 +469,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root) | |||
| 469 | seq_puts(s, ",nouser_xattr"); | 469 | seq_puts(s, ",nouser_xattr"); |
| 470 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) | 470 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) |
| 471 | seq_puts(s, ",mapchars"); | 471 | seq_puts(s, ",mapchars"); |
| 472 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR) | ||
| 473 | seq_puts(s, ",mapposix"); | ||
| 472 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) | 474 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) |
| 473 | seq_puts(s, ",sfu"); | 475 | seq_puts(s, ",sfu"); |
| 474 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | 476 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index c31ce98c1704..c63fd1dde25b 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -361,11 +361,11 @@ extern int CIFSUnixCreateHardLink(const unsigned int xid, | |||
| 361 | extern int CIFSUnixCreateSymLink(const unsigned int xid, | 361 | extern int CIFSUnixCreateSymLink(const unsigned int xid, |
| 362 | struct cifs_tcon *tcon, | 362 | struct cifs_tcon *tcon, |
| 363 | const char *fromName, const char *toName, | 363 | const char *fromName, const char *toName, |
| 364 | const struct nls_table *nls_codepage); | 364 | const struct nls_table *nls_codepage, int remap); |
| 365 | extern int CIFSSMBUnixQuerySymLink(const unsigned int xid, | 365 | extern int CIFSSMBUnixQuerySymLink(const unsigned int xid, |
| 366 | struct cifs_tcon *tcon, | 366 | struct cifs_tcon *tcon, |
| 367 | const unsigned char *searchName, char **syminfo, | 367 | const unsigned char *searchName, char **syminfo, |
| 368 | const struct nls_table *nls_codepage); | 368 | const struct nls_table *nls_codepage, int remap); |
| 369 | extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, | 369 | extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, |
| 370 | __u16 fid, char **symlinkinfo, | 370 | __u16 fid, char **symlinkinfo, |
| 371 | const struct nls_table *nls_codepage); | 371 | const struct nls_table *nls_codepage); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 84650a51c7c4..f26ffbfc64d8 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -2784,7 +2784,7 @@ copyRetry: | |||
| 2784 | int | 2784 | int |
| 2785 | CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon, | 2785 | CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon, |
| 2786 | const char *fromName, const char *toName, | 2786 | const char *fromName, const char *toName, |
| 2787 | const struct nls_table *nls_codepage) | 2787 | const struct nls_table *nls_codepage, int remap) |
| 2788 | { | 2788 | { |
| 2789 | TRANSACTION2_SPI_REQ *pSMB = NULL; | 2789 | TRANSACTION2_SPI_REQ *pSMB = NULL; |
| 2790 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | 2790 | TRANSACTION2_SPI_RSP *pSMBr = NULL; |
| @@ -2804,9 +2804,9 @@ createSymLinkRetry: | |||
| 2804 | 2804 | ||
| 2805 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 2805 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
| 2806 | name_len = | 2806 | name_len = |
| 2807 | cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName, | 2807 | cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName, |
| 2808 | /* find define for this maxpathcomponent */ | 2808 | /* find define for this maxpathcomponent */ |
| 2809 | PATH_MAX, nls_codepage); | 2809 | PATH_MAX, nls_codepage, remap); |
| 2810 | name_len++; /* trailing null */ | 2810 | name_len++; /* trailing null */ |
| 2811 | name_len *= 2; | 2811 | name_len *= 2; |
| 2812 | 2812 | ||
| @@ -2828,9 +2828,9 @@ createSymLinkRetry: | |||
| 2828 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; | 2828 | data_offset = (char *) (&pSMB->hdr.Protocol) + offset; |
| 2829 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 2829 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
| 2830 | name_len_target = | 2830 | name_len_target = |
| 2831 | cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX | 2831 | cifsConvertToUTF16((__le16 *) data_offset, toName, |
| 2832 | /* find define for this maxpathcomponent */ | 2832 | /* find define for this maxpathcomponent */ |
| 2833 | , nls_codepage); | 2833 | PATH_MAX, nls_codepage, remap); |
| 2834 | name_len_target++; /* trailing null */ | 2834 | name_len_target++; /* trailing null */ |
| 2835 | name_len_target *= 2; | 2835 | name_len_target *= 2; |
| 2836 | } else { /* BB improve the check for buffer overruns BB */ | 2836 | } else { /* BB improve the check for buffer overruns BB */ |
| @@ -3034,7 +3034,7 @@ winCreateHardLinkRetry: | |||
| 3034 | int | 3034 | int |
| 3035 | CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, | 3035 | CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, |
| 3036 | const unsigned char *searchName, char **symlinkinfo, | 3036 | const unsigned char *searchName, char **symlinkinfo, |
| 3037 | const struct nls_table *nls_codepage) | 3037 | const struct nls_table *nls_codepage, int remap) |
| 3038 | { | 3038 | { |
| 3039 | /* SMB_QUERY_FILE_UNIX_LINK */ | 3039 | /* SMB_QUERY_FILE_UNIX_LINK */ |
| 3040 | TRANSACTION2_QPI_REQ *pSMB = NULL; | 3040 | TRANSACTION2_QPI_REQ *pSMB = NULL; |
| @@ -3055,8 +3055,9 @@ querySymLinkRetry: | |||
| 3055 | 3055 | ||
| 3056 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | 3056 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { |
| 3057 | name_len = | 3057 | name_len = |
| 3058 | cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName, | 3058 | cifsConvertToUTF16((__le16 *) pSMB->FileName, |
| 3059 | PATH_MAX, nls_codepage); | 3059 | searchName, PATH_MAX, nls_codepage, |
| 3060 | remap); | ||
| 3060 | name_len++; /* trailing null */ | 3061 | name_len++; /* trailing null */ |
| 3061 | name_len *= 2; | 3062 | name_len *= 2; |
| 3062 | } else { /* BB improve the check for buffer overruns BB */ | 3063 | } else { /* BB improve the check for buffer overruns BB */ |
| @@ -4917,7 +4918,7 @@ getDFSRetry: | |||
| 4917 | strncpy(pSMB->RequestFileName, search_name, name_len); | 4918 | strncpy(pSMB->RequestFileName, search_name, name_len); |
| 4918 | } | 4919 | } |
| 4919 | 4920 | ||
| 4920 | if (ses->server && ses->server->sign) | 4921 | if (ses->server->sign) |
| 4921 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | 4922 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
| 4922 | 4923 | ||
| 4923 | pSMB->hdr.Uid = ses->Suid; | 4924 | pSMB->hdr.Uid = ses->Suid; |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f3bfe08e177b..8383d5ea4202 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -386,6 +386,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 386 | rc = generic_ip_connect(server); | 386 | rc = generic_ip_connect(server); |
| 387 | if (rc) { | 387 | if (rc) { |
| 388 | cifs_dbg(FYI, "reconnect error %d\n", rc); | 388 | cifs_dbg(FYI, "reconnect error %d\n", rc); |
| 389 | mutex_unlock(&server->srv_mutex); | ||
| 389 | msleep(3000); | 390 | msleep(3000); |
| 390 | } else { | 391 | } else { |
| 391 | atomic_inc(&tcpSesReconnectCount); | 392 | atomic_inc(&tcpSesReconnectCount); |
| @@ -393,8 +394,8 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 393 | if (server->tcpStatus != CifsExiting) | 394 | if (server->tcpStatus != CifsExiting) |
| 394 | server->tcpStatus = CifsNeedNegotiate; | 395 | server->tcpStatus = CifsNeedNegotiate; |
| 395 | spin_unlock(&GlobalMid_Lock); | 396 | spin_unlock(&GlobalMid_Lock); |
| 397 | mutex_unlock(&server->srv_mutex); | ||
| 396 | } | 398 | } |
| 397 | mutex_unlock(&server->srv_mutex); | ||
| 398 | } while (server->tcpStatus == CifsNeedReconnect); | 399 | } while (server->tcpStatus == CifsNeedReconnect); |
| 399 | 400 | ||
| 400 | return rc; | 401 | return rc; |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 338d56936f6a..c3eb998a99bd 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
| @@ -620,8 +620,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
| 620 | } | 620 | } |
| 621 | rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, | 621 | rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, |
| 622 | cifs_sb->local_nls, | 622 | cifs_sb->local_nls, |
| 623 | cifs_sb->mnt_cifs_flags & | 623 | cifs_remap(cifs_sb)); |
| 624 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 625 | if (rc) | 624 | if (rc) |
| 626 | goto mknod_out; | 625 | goto mknod_out; |
| 627 | 626 | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index cafbf10521d5..3f50cee79df9 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -140,8 +140,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
| 140 | posix_flags = cifs_posix_convert_flags(f_flags); | 140 | posix_flags = cifs_posix_convert_flags(f_flags); |
| 141 | rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data, | 141 | rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data, |
| 142 | poplock, full_path, cifs_sb->local_nls, | 142 | poplock, full_path, cifs_sb->local_nls, |
| 143 | cifs_sb->mnt_cifs_flags & | 143 | cifs_remap(cifs_sb)); |
| 144 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 145 | cifs_put_tlink(tlink); | 144 | cifs_put_tlink(tlink); |
| 146 | 145 | ||
| 147 | if (rc) | 146 | if (rc) |
| @@ -1553,8 +1552,8 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, | |||
| 1553 | rc = server->ops->mand_unlock_range(cfile, flock, xid); | 1552 | rc = server->ops->mand_unlock_range(cfile, flock, xid); |
| 1554 | 1553 | ||
| 1555 | out: | 1554 | out: |
| 1556 | if (flock->fl_flags & FL_POSIX) | 1555 | if (flock->fl_flags & FL_POSIX && !rc) |
| 1557 | posix_lock_file_wait(file, flock); | 1556 | rc = posix_lock_file_wait(file, flock); |
| 1558 | return rc; | 1557 | return rc; |
| 1559 | } | 1558 | } |
| 1560 | 1559 | ||
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 55b58112d122..f621b44cb800 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -373,8 +373,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
| 373 | 373 | ||
| 374 | /* could have done a find first instead but this returns more info */ | 374 | /* could have done a find first instead but this returns more info */ |
| 375 | rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, | 375 | rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, |
| 376 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 376 | cifs_sb->local_nls, cifs_remap(cifs_sb)); |
| 377 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 378 | cifs_put_tlink(tlink); | 377 | cifs_put_tlink(tlink); |
| 379 | 378 | ||
| 380 | if (!rc) { | 379 | if (!rc) { |
| @@ -402,9 +401,25 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
| 402 | rc = -ENOMEM; | 401 | rc = -ENOMEM; |
| 403 | } else { | 402 | } else { |
| 404 | /* we already have inode, update it */ | 403 | /* we already have inode, update it */ |
| 404 | |||
| 405 | /* if uniqueid is different, return error */ | ||
| 406 | if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && | ||
| 407 | CIFS_I(*pinode)->uniqueid != fattr.cf_uniqueid)) { | ||
| 408 | rc = -ESTALE; | ||
| 409 | goto cgiiu_exit; | ||
| 410 | } | ||
| 411 | |||
| 412 | /* if filetype is different, return error */ | ||
| 413 | if (unlikely(((*pinode)->i_mode & S_IFMT) != | ||
| 414 | (fattr.cf_mode & S_IFMT))) { | ||
| 415 | rc = -ESTALE; | ||
| 416 | goto cgiiu_exit; | ||
| 417 | } | ||
| 418 | |||
| 405 | cifs_fattr_to_inode(*pinode, &fattr); | 419 | cifs_fattr_to_inode(*pinode, &fattr); |
| 406 | } | 420 | } |
| 407 | 421 | ||
| 422 | cgiiu_exit: | ||
| 408 | return rc; | 423 | return rc; |
| 409 | } | 424 | } |
| 410 | 425 | ||
| @@ -839,6 +854,15 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, | |||
| 839 | if (!*inode) | 854 | if (!*inode) |
| 840 | rc = -ENOMEM; | 855 | rc = -ENOMEM; |
| 841 | } else { | 856 | } else { |
| 857 | /* we already have inode, update it */ | ||
| 858 | |||
| 859 | /* if filetype is different, return error */ | ||
| 860 | if (unlikely(((*inode)->i_mode & S_IFMT) != | ||
| 861 | (fattr.cf_mode & S_IFMT))) { | ||
| 862 | rc = -ESTALE; | ||
| 863 | goto cgii_exit; | ||
| 864 | } | ||
| 865 | |||
| 842 | cifs_fattr_to_inode(*inode, &fattr); | 866 | cifs_fattr_to_inode(*inode, &fattr); |
| 843 | } | 867 | } |
| 844 | 868 | ||
| @@ -2215,8 +2239,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
| 2215 | pTcon = tlink_tcon(tlink); | 2239 | pTcon = tlink_tcon(tlink); |
| 2216 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, | 2240 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, |
| 2217 | cifs_sb->local_nls, | 2241 | cifs_sb->local_nls, |
| 2218 | cifs_sb->mnt_cifs_flags & | 2242 | cifs_remap(cifs_sb)); |
| 2219 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 2220 | cifs_put_tlink(tlink); | 2243 | cifs_put_tlink(tlink); |
| 2221 | } | 2244 | } |
| 2222 | 2245 | ||
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 252e672d5604..e6c707cc62b3 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
| @@ -717,7 +717,8 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
| 717 | rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname); | 717 | rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname); |
| 718 | else if (pTcon->unix_ext) | 718 | else if (pTcon->unix_ext) |
| 719 | rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, | 719 | rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, |
| 720 | cifs_sb->local_nls); | 720 | cifs_sb->local_nls, |
| 721 | cifs_remap(cifs_sb)); | ||
| 721 | /* else | 722 | /* else |
| 722 | rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName, | 723 | rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName, |
| 723 | cifs_sb_target->local_nls); */ | 724 | cifs_sb_target->local_nls); */ |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index b4a47237486b..b1eede3678a9 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
| @@ -90,6 +90,8 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, | |||
| 90 | if (dentry) { | 90 | if (dentry) { |
| 91 | inode = d_inode(dentry); | 91 | inode = d_inode(dentry); |
| 92 | if (inode) { | 92 | if (inode) { |
| 93 | if (d_mountpoint(dentry)) | ||
| 94 | goto out; | ||
| 93 | /* | 95 | /* |
| 94 | * If we're generating inode numbers, then we don't | 96 | * If we're generating inode numbers, then we don't |
| 95 | * want to clobber the existing one with the one that | 97 | * want to clobber the existing one with the one that |
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 7bfdd6066276..fc537c29044e 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c | |||
| @@ -960,7 +960,8 @@ cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 960 | /* Check for unix extensions */ | 960 | /* Check for unix extensions */ |
| 961 | if (cap_unix(tcon->ses)) { | 961 | if (cap_unix(tcon->ses)) { |
| 962 | rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path, | 962 | rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path, |
| 963 | cifs_sb->local_nls); | 963 | cifs_sb->local_nls, |
| 964 | cifs_remap(cifs_sb)); | ||
| 964 | if (rc == -EREMOTE) | 965 | if (rc == -EREMOTE) |
| 965 | rc = cifs_unix_dfs_readlink(xid, tcon, full_path, | 966 | rc = cifs_unix_dfs_readlink(xid, tcon, full_path, |
| 966 | target_path, | 967 | target_path, |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 65cd7a84c8bc..54cbe19d9c08 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
| @@ -110,7 +110,7 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , | |||
| 110 | 110 | ||
| 111 | /* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */ | 111 | /* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */ |
| 112 | /* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */ | 112 | /* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */ |
| 113 | if ((tcon->ses) && | 113 | if ((tcon->ses) && (tcon->ses->server) && |
| 114 | (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) | 114 | (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) |
| 115 | hdr->CreditCharge = cpu_to_le16(1); | 115 | hdr->CreditCharge = cpu_to_le16(1); |
| 116 | /* else CreditCharge MBZ */ | 116 | /* else CreditCharge MBZ */ |
diff --git a/fs/omfs/bitmap.c b/fs/omfs/bitmap.c index 082234581d05..83f4e76511c2 100644 --- a/fs/omfs/bitmap.c +++ b/fs/omfs/bitmap.c | |||
| @@ -159,7 +159,7 @@ int omfs_allocate_range(struct super_block *sb, | |||
| 159 | goto out; | 159 | goto out; |
| 160 | 160 | ||
| 161 | found: | 161 | found: |
| 162 | *return_block = i * bits_per_entry + bit; | 162 | *return_block = (u64) i * bits_per_entry + bit; |
| 163 | *return_size = run; | 163 | *return_size = run; |
| 164 | ret = set_run(sb, i, bits_per_entry, bit, run, 1); | 164 | ret = set_run(sb, i, bits_per_entry, bit, run, 1); |
| 165 | 165 | ||
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index 138321b0c6c2..3d935c81789a 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c | |||
| @@ -306,7 +306,8 @@ static const struct super_operations omfs_sops = { | |||
| 306 | */ | 306 | */ |
| 307 | static int omfs_get_imap(struct super_block *sb) | 307 | static int omfs_get_imap(struct super_block *sb) |
| 308 | { | 308 | { |
| 309 | unsigned int bitmap_size, count, array_size; | 309 | unsigned int bitmap_size, array_size; |
| 310 | int count; | ||
| 310 | struct omfs_sb_info *sbi = OMFS_SB(sb); | 311 | struct omfs_sb_info *sbi = OMFS_SB(sb); |
| 311 | struct buffer_head *bh; | 312 | struct buffer_head *bh; |
| 312 | unsigned long **ptr; | 313 | unsigned long **ptr; |
| @@ -359,7 +360,7 @@ nomem: | |||
| 359 | } | 360 | } |
| 360 | 361 | ||
| 361 | enum { | 362 | enum { |
| 362 | Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask | 363 | Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask, Opt_err |
| 363 | }; | 364 | }; |
| 364 | 365 | ||
| 365 | static const match_table_t tokens = { | 366 | static const match_table_t tokens = { |
| @@ -368,6 +369,7 @@ static const match_table_t tokens = { | |||
| 368 | {Opt_umask, "umask=%o"}, | 369 | {Opt_umask, "umask=%o"}, |
| 369 | {Opt_dmask, "dmask=%o"}, | 370 | {Opt_dmask, "dmask=%o"}, |
| 370 | {Opt_fmask, "fmask=%o"}, | 371 | {Opt_fmask, "fmask=%o"}, |
| 372 | {Opt_err, NULL}, | ||
| 371 | }; | 373 | }; |
| 372 | 374 | ||
| 373 | static int parse_options(char *options, struct omfs_sb_info *sbi) | 375 | static int parse_options(char *options, struct omfs_sb_info *sbi) |
| @@ -548,8 +550,10 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 548 | } | 550 | } |
| 549 | 551 | ||
| 550 | sb->s_root = d_make_root(root); | 552 | sb->s_root = d_make_root(root); |
| 551 | if (!sb->s_root) | 553 | if (!sb->s_root) { |
| 554 | ret = -ENOMEM; | ||
| 552 | goto out_brelse_bh2; | 555 | goto out_brelse_bh2; |
| 556 | } | ||
| 553 | printk(KERN_DEBUG "omfs: Mounted volume %s\n", omfs_rb->r_name); | 557 | printk(KERN_DEBUG "omfs: Mounted volume %s\n", omfs_rb->r_name); |
| 554 | 558 | ||
| 555 | ret = 0; | 559 | ret = 0; |
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 24f640441bd9..84d693d37428 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c | |||
| @@ -299,6 +299,9 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, | |||
| 299 | struct cred *override_cred; | 299 | struct cred *override_cred; |
| 300 | char *link = NULL; | 300 | char *link = NULL; |
| 301 | 301 | ||
| 302 | if (WARN_ON(!workdir)) | ||
| 303 | return -EROFS; | ||
| 304 | |||
| 302 | ovl_path_upper(parent, &parentpath); | 305 | ovl_path_upper(parent, &parentpath); |
| 303 | upperdir = parentpath.dentry; | 306 | upperdir = parentpath.dentry; |
| 304 | 307 | ||
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index d139405d2bfa..692ceda3bc21 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c | |||
| @@ -222,6 +222,9 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry, | |||
| 222 | struct kstat stat; | 222 | struct kstat stat; |
| 223 | int err; | 223 | int err; |
| 224 | 224 | ||
| 225 | if (WARN_ON(!workdir)) | ||
| 226 | return ERR_PTR(-EROFS); | ||
| 227 | |||
| 225 | err = ovl_lock_rename_workdir(workdir, upperdir); | 228 | err = ovl_lock_rename_workdir(workdir, upperdir); |
| 226 | if (err) | 229 | if (err) |
| 227 | goto out; | 230 | goto out; |
| @@ -322,6 +325,9 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, | |||
| 322 | struct dentry *newdentry; | 325 | struct dentry *newdentry; |
| 323 | int err; | 326 | int err; |
| 324 | 327 | ||
| 328 | if (WARN_ON(!workdir)) | ||
| 329 | return -EROFS; | ||
| 330 | |||
| 325 | err = ovl_lock_rename_workdir(workdir, upperdir); | 331 | err = ovl_lock_rename_workdir(workdir, upperdir); |
| 326 | if (err) | 332 | if (err) |
| 327 | goto out; | 333 | goto out; |
| @@ -506,11 +512,28 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir) | |||
| 506 | struct dentry *opaquedir = NULL; | 512 | struct dentry *opaquedir = NULL; |
| 507 | int err; | 513 | int err; |
| 508 | 514 | ||
| 509 | if (is_dir && OVL_TYPE_MERGE_OR_LOWER(ovl_path_type(dentry))) { | 515 | if (WARN_ON(!workdir)) |
| 510 | opaquedir = ovl_check_empty_and_clear(dentry); | 516 | return -EROFS; |
| 511 | err = PTR_ERR(opaquedir); | 517 | |
| 512 | if (IS_ERR(opaquedir)) | 518 | if (is_dir) { |
| 513 | goto out; | 519 | if (OVL_TYPE_MERGE_OR_LOWER(ovl_path_type(dentry))) { |
| 520 | opaquedir = ovl_check_empty_and_clear(dentry); | ||
| 521 | err = PTR_ERR(opaquedir); | ||
| 522 | if (IS_ERR(opaquedir)) | ||
| 523 | goto out; | ||
| 524 | } else { | ||
| 525 | LIST_HEAD(list); | ||
| 526 | |||
| 527 | /* | ||
| 528 | * When removing an empty opaque directory, then it | ||
| 529 | * makes no sense to replace it with an exact replica of | ||
| 530 | * itself. But emptiness still needs to be checked. | ||
| 531 | */ | ||
| 532 | err = ovl_check_empty_dir(dentry, &list); | ||
| 533 | ovl_cache_free(&list); | ||
| 534 | if (err) | ||
| 535 | goto out; | ||
| 536 | } | ||
| 514 | } | 537 | } |
| 515 | 538 | ||
| 516 | err = ovl_lock_rename_workdir(workdir, upperdir); | 539 | err = ovl_lock_rename_workdir(workdir, upperdir); |
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 5f0d1993e6e3..bf8537c7f455 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c | |||
| @@ -529,7 +529,7 @@ static int ovl_remount(struct super_block *sb, int *flags, char *data) | |||
| 529 | { | 529 | { |
| 530 | struct ovl_fs *ufs = sb->s_fs_info; | 530 | struct ovl_fs *ufs = sb->s_fs_info; |
| 531 | 531 | ||
| 532 | if (!(*flags & MS_RDONLY) && !ufs->upper_mnt) | 532 | if (!(*flags & MS_RDONLY) && (!ufs->upper_mnt || !ufs->workdir)) |
| 533 | return -EROFS; | 533 | return -EROFS; |
| 534 | 534 | ||
| 535 | return 0; | 535 | return 0; |
| @@ -925,9 +925,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
| 925 | ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry); | 925 | ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry); |
| 926 | err = PTR_ERR(ufs->workdir); | 926 | err = PTR_ERR(ufs->workdir); |
| 927 | if (IS_ERR(ufs->workdir)) { | 927 | if (IS_ERR(ufs->workdir)) { |
| 928 | pr_err("overlayfs: failed to create directory %s/%s\n", | 928 | pr_warn("overlayfs: failed to create directory %s/%s (errno: %i); mounting read-only\n", |
| 929 | ufs->config.workdir, OVL_WORKDIR_NAME); | 929 | ufs->config.workdir, OVL_WORKDIR_NAME, -err); |
| 930 | goto out_put_upper_mnt; | 930 | sb->s_flags |= MS_RDONLY; |
| 931 | ufs->workdir = NULL; | ||
| 931 | } | 932 | } |
| 932 | } | 933 | } |
| 933 | 934 | ||
| @@ -997,7 +998,6 @@ out_put_lower_mnt: | |||
| 997 | kfree(ufs->lower_mnt); | 998 | kfree(ufs->lower_mnt); |
| 998 | out_put_workdir: | 999 | out_put_workdir: |
| 999 | dput(ufs->workdir); | 1000 | dput(ufs->workdir); |
| 1000 | out_put_upper_mnt: | ||
| 1001 | mntput(ufs->upper_mnt); | 1001 | mntput(ufs->upper_mnt); |
| 1002 | out_put_lowerpath: | 1002 | out_put_lowerpath: |
| 1003 | for (i = 0; i < numlower; i++) | 1003 | for (i = 0; i < numlower; i++) |
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 04e79d57bca6..e9d401ce93bb 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c | |||
| @@ -574,8 +574,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff) | |||
| 574 | * After the last attribute is removed revert to original inode format, | 574 | * After the last attribute is removed revert to original inode format, |
| 575 | * making all literal area available to the data fork once more. | 575 | * making all literal area available to the data fork once more. |
| 576 | */ | 576 | */ |
| 577 | STATIC void | 577 | void |
| 578 | xfs_attr_fork_reset( | 578 | xfs_attr_fork_remove( |
| 579 | struct xfs_inode *ip, | 579 | struct xfs_inode *ip, |
| 580 | struct xfs_trans *tp) | 580 | struct xfs_trans *tp) |
| 581 | { | 581 | { |
| @@ -641,7 +641,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args) | |||
| 641 | (mp->m_flags & XFS_MOUNT_ATTR2) && | 641 | (mp->m_flags & XFS_MOUNT_ATTR2) && |
| 642 | (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) && | 642 | (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) && |
| 643 | !(args->op_flags & XFS_DA_OP_ADDNAME)) { | 643 | !(args->op_flags & XFS_DA_OP_ADDNAME)) { |
| 644 | xfs_attr_fork_reset(dp, args->trans); | 644 | xfs_attr_fork_remove(dp, args->trans); |
| 645 | } else { | 645 | } else { |
| 646 | xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); | 646 | xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); |
| 647 | dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); | 647 | dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); |
| @@ -905,7 +905,7 @@ xfs_attr3_leaf_to_shortform( | |||
| 905 | if (forkoff == -1) { | 905 | if (forkoff == -1) { |
| 906 | ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2); | 906 | ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2); |
| 907 | ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE); | 907 | ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE); |
| 908 | xfs_attr_fork_reset(dp, args->trans); | 908 | xfs_attr_fork_remove(dp, args->trans); |
| 909 | goto out; | 909 | goto out; |
| 910 | } | 910 | } |
| 911 | 911 | ||
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h index 025c4b820c03..882c8d338891 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.h +++ b/fs/xfs/libxfs/xfs_attr_leaf.h | |||
| @@ -53,7 +53,7 @@ int xfs_attr_shortform_remove(struct xfs_da_args *args); | |||
| 53 | int xfs_attr_shortform_list(struct xfs_attr_list_context *context); | 53 | int xfs_attr_shortform_list(struct xfs_attr_list_context *context); |
| 54 | int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp); | 54 | int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp); |
| 55 | int xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes); | 55 | int xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes); |
| 56 | 56 | void xfs_attr_fork_remove(struct xfs_inode *ip, struct xfs_trans *tp); | |
| 57 | 57 | ||
| 58 | /* | 58 | /* |
| 59 | * Internal routines when attribute fork size == XFS_LBSIZE(mp). | 59 | * Internal routines when attribute fork size == XFS_LBSIZE(mp). |
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index aeffeaaac0ec..f1026e86dabc 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c | |||
| @@ -3224,12 +3224,24 @@ xfs_bmap_extsize_align( | |||
| 3224 | align_alen += temp; | 3224 | align_alen += temp; |
| 3225 | align_off -= temp; | 3225 | align_off -= temp; |
| 3226 | } | 3226 | } |
| 3227 | |||
| 3228 | /* Same adjustment for the end of the requested area. */ | ||
| 3229 | temp = (align_alen % extsz); | ||
| 3230 | if (temp) | ||
| 3231 | align_alen += extsz - temp; | ||
| 3232 | |||
| 3227 | /* | 3233 | /* |
| 3228 | * Same adjustment for the end of the requested area. | 3234 | * For large extent hint sizes, the aligned extent might be larger than |
| 3235 | * MAXEXTLEN. In that case, reduce the size by an extsz so that it pulls | ||
| 3236 | * the length back under MAXEXTLEN. The outer allocation loops handle | ||
| 3237 | * short allocation just fine, so it is safe to do this. We only want to | ||
| 3238 | * do it when we are forced to, though, because it means more allocation | ||
| 3239 | * operations are required. | ||
| 3229 | */ | 3240 | */ |
| 3230 | if ((temp = (align_alen % extsz))) { | 3241 | while (align_alen > MAXEXTLEN) |
| 3231 | align_alen += extsz - temp; | 3242 | align_alen -= extsz; |
| 3232 | } | 3243 | ASSERT(align_alen <= MAXEXTLEN); |
| 3244 | |||
| 3233 | /* | 3245 | /* |
| 3234 | * If the previous block overlaps with this proposed allocation | 3246 | * If the previous block overlaps with this proposed allocation |
| 3235 | * then move the start forward without adjusting the length. | 3247 | * then move the start forward without adjusting the length. |
| @@ -3318,7 +3330,9 @@ xfs_bmap_extsize_align( | |||
| 3318 | return -EINVAL; | 3330 | return -EINVAL; |
| 3319 | } else { | 3331 | } else { |
| 3320 | ASSERT(orig_off >= align_off); | 3332 | ASSERT(orig_off >= align_off); |
| 3321 | ASSERT(orig_end <= align_off + align_alen); | 3333 | /* see MAXEXTLEN handling above */ |
| 3334 | ASSERT(orig_end <= align_off + align_alen || | ||
| 3335 | align_alen + extsz > MAXEXTLEN); | ||
| 3322 | } | 3336 | } |
| 3323 | 3337 | ||
| 3324 | #ifdef DEBUG | 3338 | #ifdef DEBUG |
| @@ -4099,13 +4113,6 @@ xfs_bmapi_reserve_delalloc( | |||
| 4099 | /* Figure out the extent size, adjust alen */ | 4113 | /* Figure out the extent size, adjust alen */ |
| 4100 | extsz = xfs_get_extsz_hint(ip); | 4114 | extsz = xfs_get_extsz_hint(ip); |
| 4101 | if (extsz) { | 4115 | if (extsz) { |
| 4102 | /* | ||
| 4103 | * Make sure we don't exceed a single extent length when we | ||
| 4104 | * align the extent by reducing length we are going to | ||
| 4105 | * allocate by the maximum amount extent size aligment may | ||
| 4106 | * require. | ||
| 4107 | */ | ||
| 4108 | alen = XFS_FILBLKS_MIN(len, MAXEXTLEN - (2 * extsz - 1)); | ||
| 4109 | error = xfs_bmap_extsize_align(mp, got, prev, extsz, rt, eof, | 4116 | error = xfs_bmap_extsize_align(mp, got, prev, extsz, rt, eof, |
| 4110 | 1, 0, &aoff, &alen); | 4117 | 1, 0, &aoff, &alen); |
| 4111 | ASSERT(!error); | 4118 | ASSERT(!error); |
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index 07349a183a11..1c9e75521250 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c | |||
| @@ -376,7 +376,7 @@ xfs_ialloc_ag_alloc( | |||
| 376 | */ | 376 | */ |
| 377 | newlen = args.mp->m_ialloc_inos; | 377 | newlen = args.mp->m_ialloc_inos; |
| 378 | if (args.mp->m_maxicount && | 378 | if (args.mp->m_maxicount && |
| 379 | percpu_counter_read(&args.mp->m_icount) + newlen > | 379 | percpu_counter_read_positive(&args.mp->m_icount) + newlen > |
| 380 | args.mp->m_maxicount) | 380 | args.mp->m_maxicount) |
| 381 | return -ENOSPC; | 381 | return -ENOSPC; |
| 382 | args.minlen = args.maxlen = args.mp->m_ialloc_blks; | 382 | args.minlen = args.maxlen = args.mp->m_ialloc_blks; |
| @@ -1339,10 +1339,13 @@ xfs_dialloc( | |||
| 1339 | * If we have already hit the ceiling of inode blocks then clear | 1339 | * If we have already hit the ceiling of inode blocks then clear |
| 1340 | * okalloc so we scan all available agi structures for a free | 1340 | * okalloc so we scan all available agi structures for a free |
| 1341 | * inode. | 1341 | * inode. |
| 1342 | * | ||
| 1343 | * Read rough value of mp->m_icount by percpu_counter_read_positive, | ||
| 1344 | * which will sacrifice the preciseness but improve the performance. | ||
| 1342 | */ | 1345 | */ |
| 1343 | if (mp->m_maxicount && | 1346 | if (mp->m_maxicount && |
| 1344 | percpu_counter_read(&mp->m_icount) + mp->m_ialloc_inos > | 1347 | percpu_counter_read_positive(&mp->m_icount) + mp->m_ialloc_inos |
| 1345 | mp->m_maxicount) { | 1348 | > mp->m_maxicount) { |
| 1346 | noroom = 1; | 1349 | noroom = 1; |
| 1347 | okalloc = 0; | 1350 | okalloc = 0; |
| 1348 | } | 1351 | } |
diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c index f9c1c64782d3..3fbf167cfb4c 100644 --- a/fs/xfs/xfs_attr_inactive.c +++ b/fs/xfs/xfs_attr_inactive.c | |||
| @@ -380,23 +380,31 @@ xfs_attr3_root_inactive( | |||
| 380 | return error; | 380 | return error; |
| 381 | } | 381 | } |
| 382 | 382 | ||
| 383 | /* | ||
| 384 | * xfs_attr_inactive kills all traces of an attribute fork on an inode. It | ||
| 385 | * removes both the on-disk and in-memory inode fork. Note that this also has to | ||
| 386 | * handle the condition of inodes without attributes but with an attribute fork | ||
| 387 | * configured, so we can't use xfs_inode_hasattr() here. | ||
| 388 | * | ||
| 389 | * The in-memory attribute fork is removed even on error. | ||
| 390 | */ | ||
| 383 | int | 391 | int |
| 384 | xfs_attr_inactive(xfs_inode_t *dp) | 392 | xfs_attr_inactive( |
| 393 | struct xfs_inode *dp) | ||
| 385 | { | 394 | { |
| 386 | xfs_trans_t *trans; | 395 | struct xfs_trans *trans; |
| 387 | xfs_mount_t *mp; | 396 | struct xfs_mount *mp; |
| 388 | int error; | 397 | int cancel_flags = 0; |
| 398 | int lock_mode = XFS_ILOCK_SHARED; | ||
| 399 | int error = 0; | ||
| 389 | 400 | ||
| 390 | mp = dp->i_mount; | 401 | mp = dp->i_mount; |
| 391 | ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); | 402 | ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); |
| 392 | 403 | ||
| 393 | xfs_ilock(dp, XFS_ILOCK_SHARED); | 404 | xfs_ilock(dp, lock_mode); |
| 394 | if (!xfs_inode_hasattr(dp) || | 405 | if (!XFS_IFORK_Q(dp)) |
| 395 | dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | 406 | goto out_destroy_fork; |
| 396 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | 407 | xfs_iunlock(dp, lock_mode); |
| 397 | return 0; | ||
| 398 | } | ||
| 399 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | ||
| 400 | 408 | ||
| 401 | /* | 409 | /* |
| 402 | * Start our first transaction of the day. | 410 | * Start our first transaction of the day. |
| @@ -408,13 +416,18 @@ xfs_attr_inactive(xfs_inode_t *dp) | |||
| 408 | * the inode in every transaction to let it float upward through | 416 | * the inode in every transaction to let it float upward through |
| 409 | * the log. | 417 | * the log. |
| 410 | */ | 418 | */ |
| 419 | lock_mode = 0; | ||
| 411 | trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL); | 420 | trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL); |
| 412 | error = xfs_trans_reserve(trans, &M_RES(mp)->tr_attrinval, 0, 0); | 421 | error = xfs_trans_reserve(trans, &M_RES(mp)->tr_attrinval, 0, 0); |
| 413 | if (error) { | 422 | if (error) |
| 414 | xfs_trans_cancel(trans, 0); | 423 | goto out_cancel; |
| 415 | return error; | 424 | |
| 416 | } | 425 | lock_mode = XFS_ILOCK_EXCL; |
| 417 | xfs_ilock(dp, XFS_ILOCK_EXCL); | 426 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT; |
| 427 | xfs_ilock(dp, lock_mode); | ||
| 428 | |||
| 429 | if (!XFS_IFORK_Q(dp)) | ||
| 430 | goto out_cancel; | ||
| 418 | 431 | ||
| 419 | /* | 432 | /* |
| 420 | * No need to make quota reservations here. We expect to release some | 433 | * No need to make quota reservations here. We expect to release some |
| @@ -422,29 +435,31 @@ xfs_attr_inactive(xfs_inode_t *dp) | |||
| 422 | */ | 435 | */ |
| 423 | xfs_trans_ijoin(trans, dp, 0); | 436 | xfs_trans_ijoin(trans, dp, 0); |
| 424 | 437 | ||
| 425 | /* | 438 | /* invalidate and truncate the attribute fork extents */ |
| 426 | * Decide on what work routines to call based on the inode size. | 439 | if (dp->i_d.di_aformat != XFS_DINODE_FMT_LOCAL) { |
| 427 | */ | 440 | error = xfs_attr3_root_inactive(&trans, dp); |
| 428 | if (!xfs_inode_hasattr(dp) || | 441 | if (error) |
| 429 | dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | 442 | goto out_cancel; |
| 430 | error = 0; | 443 | |
| 431 | goto out; | 444 | error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0); |
| 445 | if (error) | ||
| 446 | goto out_cancel; | ||
| 432 | } | 447 | } |
| 433 | error = xfs_attr3_root_inactive(&trans, dp); | ||
| 434 | if (error) | ||
| 435 | goto out; | ||
| 436 | 448 | ||
| 437 | error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0); | 449 | /* Reset the attribute fork - this also destroys the in-core fork */ |
| 438 | if (error) | 450 | xfs_attr_fork_remove(dp, trans); |
| 439 | goto out; | ||
| 440 | 451 | ||
| 441 | error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES); | 452 | error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES); |
| 442 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 453 | xfs_iunlock(dp, lock_mode); |
| 443 | |||
| 444 | return error; | 454 | return error; |
| 445 | 455 | ||
| 446 | out: | 456 | out_cancel: |
| 447 | xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); | 457 | xfs_trans_cancel(trans, cancel_flags); |
| 448 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 458 | out_destroy_fork: |
| 459 | /* kill the in-core attr fork before we drop the inode lock */ | ||
| 460 | if (dp->i_afp) | ||
| 461 | xfs_idestroy_fork(dp, XFS_ATTR_FORK); | ||
| 462 | if (lock_mode) | ||
| 463 | xfs_iunlock(dp, lock_mode); | ||
| 449 | return error; | 464 | return error; |
| 450 | } | 465 | } |
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 8121e75352ee..3b7591224f4a 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
| @@ -124,7 +124,7 @@ xfs_iozero( | |||
| 124 | status = 0; | 124 | status = 0; |
| 125 | } while (count); | 125 | } while (count); |
| 126 | 126 | ||
| 127 | return (-status); | 127 | return status; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | int | 130 | int |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index d6ebc85192b7..539a85fddbc2 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -1946,21 +1946,17 @@ xfs_inactive( | |||
| 1946 | /* | 1946 | /* |
| 1947 | * If there are attributes associated with the file then blow them away | 1947 | * If there are attributes associated with the file then blow them away |
| 1948 | * now. The code calls a routine that recursively deconstructs the | 1948 | * now. The code calls a routine that recursively deconstructs the |
| 1949 | * attribute fork. We need to just commit the current transaction | 1949 | * attribute fork. If also blows away the in-core attribute fork. |
| 1950 | * because we can't use it for xfs_attr_inactive(). | ||
| 1951 | */ | 1950 | */ |
| 1952 | if (ip->i_d.di_anextents > 0) { | 1951 | if (XFS_IFORK_Q(ip)) { |
| 1953 | ASSERT(ip->i_d.di_forkoff != 0); | ||
| 1954 | |||
| 1955 | error = xfs_attr_inactive(ip); | 1952 | error = xfs_attr_inactive(ip); |
| 1956 | if (error) | 1953 | if (error) |
| 1957 | return; | 1954 | return; |
| 1958 | } | 1955 | } |
| 1959 | 1956 | ||
| 1960 | if (ip->i_afp) | 1957 | ASSERT(!ip->i_afp); |
| 1961 | xfs_idestroy_fork(ip, XFS_ATTR_FORK); | ||
| 1962 | |||
| 1963 | ASSERT(ip->i_d.di_anextents == 0); | 1958 | ASSERT(ip->i_d.di_anextents == 0); |
| 1959 | ASSERT(ip->i_d.di_forkoff == 0); | ||
| 1964 | 1960 | ||
| 1965 | /* | 1961 | /* |
| 1966 | * Free the inode. | 1962 | * Free the inode. |
| @@ -2883,7 +2879,13 @@ xfs_rename_alloc_whiteout( | |||
| 2883 | if (error) | 2879 | if (error) |
| 2884 | return error; | 2880 | return error; |
| 2885 | 2881 | ||
| 2886 | /* Satisfy xfs_bumplink that this is a real tmpfile */ | 2882 | /* |
| 2883 | * Prepare the tmpfile inode as if it were created through the VFS. | ||
| 2884 | * Otherwise, the link increment paths will complain about nlink 0->1. | ||
| 2885 | * Drop the link count as done by d_tmpfile(), complete the inode setup | ||
| 2886 | * and flag it as linkable. | ||
| 2887 | */ | ||
| 2888 | drop_nlink(VFS_I(tmpfile)); | ||
| 2887 | xfs_finish_inode_setup(tmpfile); | 2889 | xfs_finish_inode_setup(tmpfile); |
| 2888 | VFS_I(tmpfile)->i_state |= I_LINKABLE; | 2890 | VFS_I(tmpfile)->i_state |= I_LINKABLE; |
| 2889 | 2891 | ||
| @@ -3151,7 +3153,7 @@ xfs_rename( | |||
| 3151 | * intermediate state on disk. | 3153 | * intermediate state on disk. |
| 3152 | */ | 3154 | */ |
| 3153 | if (wip) { | 3155 | if (wip) { |
| 3154 | ASSERT(wip->i_d.di_nlink == 0); | 3156 | ASSERT(VFS_I(wip)->i_nlink == 0 && wip->i_d.di_nlink == 0); |
| 3155 | error = xfs_bumplink(tp, wip); | 3157 | error = xfs_bumplink(tp, wip); |
| 3156 | if (error) | 3158 | if (error) |
| 3157 | goto out_trans_abort; | 3159 | goto out_trans_abort; |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 2ce7ee3b4ec1..6f23fbdfb365 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
| @@ -1084,14 +1084,18 @@ xfs_log_sbcount(xfs_mount_t *mp) | |||
| 1084 | return xfs_sync_sb(mp, true); | 1084 | return xfs_sync_sb(mp, true); |
| 1085 | } | 1085 | } |
| 1086 | 1086 | ||
| 1087 | /* | ||
| 1088 | * Deltas for the inode count are +/-64, hence we use a large batch size | ||
| 1089 | * of 128 so we don't need to take the counter lock on every update. | ||
| 1090 | */ | ||
| 1091 | #define XFS_ICOUNT_BATCH 128 | ||
| 1087 | int | 1092 | int |
| 1088 | xfs_mod_icount( | 1093 | xfs_mod_icount( |
| 1089 | struct xfs_mount *mp, | 1094 | struct xfs_mount *mp, |
| 1090 | int64_t delta) | 1095 | int64_t delta) |
| 1091 | { | 1096 | { |
| 1092 | /* deltas are +/-64, hence the large batch size of 128. */ | 1097 | __percpu_counter_add(&mp->m_icount, delta, XFS_ICOUNT_BATCH); |
| 1093 | __percpu_counter_add(&mp->m_icount, delta, 128); | 1098 | if (__percpu_counter_compare(&mp->m_icount, 0, XFS_ICOUNT_BATCH) < 0) { |
| 1094 | if (percpu_counter_compare(&mp->m_icount, 0) < 0) { | ||
| 1095 | ASSERT(0); | 1099 | ASSERT(0); |
| 1096 | percpu_counter_add(&mp->m_icount, -delta); | 1100 | percpu_counter_add(&mp->m_icount, -delta); |
| 1097 | return -EINVAL; | 1101 | return -EINVAL; |
| @@ -1113,6 +1117,14 @@ xfs_mod_ifree( | |||
| 1113 | return 0; | 1117 | return 0; |
| 1114 | } | 1118 | } |
| 1115 | 1119 | ||
| 1120 | /* | ||
| 1121 | * Deltas for the block count can vary from 1 to very large, but lock contention | ||
| 1122 | * only occurs on frequent small block count updates such as in the delayed | ||
| 1123 | * allocation path for buffered writes (page a time updates). Hence we set | ||
| 1124 | * a large batch count (1024) to minimise global counter updates except when | ||
| 1125 | * we get near to ENOSPC and we have to be very accurate with our updates. | ||
| 1126 | */ | ||
| 1127 | #define XFS_FDBLOCKS_BATCH 1024 | ||
| 1116 | int | 1128 | int |
| 1117 | xfs_mod_fdblocks( | 1129 | xfs_mod_fdblocks( |
| 1118 | struct xfs_mount *mp, | 1130 | struct xfs_mount *mp, |
| @@ -1151,25 +1163,19 @@ xfs_mod_fdblocks( | |||
| 1151 | * Taking blocks away, need to be more accurate the closer we | 1163 | * Taking blocks away, need to be more accurate the closer we |
| 1152 | * are to zero. | 1164 | * are to zero. |
| 1153 | * | 1165 | * |
| 1154 | * batch size is set to a maximum of 1024 blocks - if we are | ||
| 1155 | * allocating of freeing extents larger than this then we aren't | ||
| 1156 | * going to be hammering the counter lock so a lock per update | ||
| 1157 | * is not a problem. | ||
| 1158 | * | ||
| 1159 | * If the counter has a value of less than 2 * max batch size, | 1166 | * If the counter has a value of less than 2 * max batch size, |
| 1160 | * then make everything serialise as we are real close to | 1167 | * then make everything serialise as we are real close to |
| 1161 | * ENOSPC. | 1168 | * ENOSPC. |
| 1162 | */ | 1169 | */ |
| 1163 | #define __BATCH 1024 | 1170 | if (__percpu_counter_compare(&mp->m_fdblocks, 2 * XFS_FDBLOCKS_BATCH, |
| 1164 | if (percpu_counter_compare(&mp->m_fdblocks, 2 * __BATCH) < 0) | 1171 | XFS_FDBLOCKS_BATCH) < 0) |
| 1165 | batch = 1; | 1172 | batch = 1; |
| 1166 | else | 1173 | else |
| 1167 | batch = __BATCH; | 1174 | batch = XFS_FDBLOCKS_BATCH; |
| 1168 | #undef __BATCH | ||
| 1169 | 1175 | ||
| 1170 | __percpu_counter_add(&mp->m_fdblocks, delta, batch); | 1176 | __percpu_counter_add(&mp->m_fdblocks, delta, batch); |
| 1171 | if (percpu_counter_compare(&mp->m_fdblocks, | 1177 | if (__percpu_counter_compare(&mp->m_fdblocks, XFS_ALLOC_SET_ASIDE(mp), |
| 1172 | XFS_ALLOC_SET_ASIDE(mp)) >= 0) { | 1178 | XFS_FDBLOCKS_BATCH) >= 0) { |
| 1173 | /* we had space! */ | 1179 | /* we had space! */ |
| 1174 | return 0; | 1180 | return 0; |
| 1175 | } | 1181 | } |
