diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/Kconfig.binfmt | 8 | ||||
-rw-r--r-- | fs/Makefile | 3 | ||||
-rw-r--r-- | fs/binfmt_aout.c | 54 | ||||
-rw-r--r-- | fs/binfmt_elf.c | 149 | ||||
-rw-r--r-- | fs/binfmt_elf_fdpic.c | 6 | ||||
-rw-r--r-- | fs/binfmt_flat.c | 2 | ||||
-rw-r--r-- | fs/compat_binfmt_elf.c | 7 | ||||
-rw-r--r-- | fs/coredump.c | 20 | ||||
-rw-r--r-- | fs/coredump.h | 6 | ||||
-rw-r--r-- | fs/eventpoll.c | 38 | ||||
-rw-r--r-- | fs/exec.c | 3 | ||||
-rw-r--r-- | fs/fat/Makefile | 2 | ||||
-rw-r--r-- | fs/fat/cache.c | 10 | ||||
-rw-r--r-- | fs/fat/dir.c | 56 | ||||
-rw-r--r-- | fs/fat/fat.h | 97 | ||||
-rw-r--r-- | fs/fat/fatent.c | 13 | ||||
-rw-r--r-- | fs/fat/inode.c | 187 | ||||
-rw-r--r-- | fs/fat/namei_msdos.c | 7 | ||||
-rw-r--r-- | fs/fat/namei_vfat.c | 5 | ||||
-rw-r--r-- | fs/fat/nfs.c | 101 | ||||
-rw-r--r-- | fs/hpfs/anode.c | 6 | ||||
-rw-r--r-- | fs/hpfs/dnode.c | 28 | ||||
-rw-r--r-- | fs/omfs/file.c | 5 | ||||
-rw-r--r-- | fs/proc/generic.c | 15 | ||||
-rw-r--r-- | fs/proc/inode.c | 1 | ||||
-rw-r--r-- | fs/proc/internal.h | 2 | ||||
-rw-r--r-- | fs/proc/proc_sysctl.c | 3 | ||||
-rw-r--r-- | fs/proc/root.c | 2 | ||||
-rw-r--r-- | fs/super.c | 2 |
29 files changed, 531 insertions, 307 deletions
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index 022574202749..0efd1524b977 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt | |||
@@ -164,3 +164,11 @@ config BINFMT_MISC | |||
164 | You may say M here for module support and later load the module when | 164 | You may say M here for module support and later load the module when |
165 | you have use for it; the module is called binfmt_misc. If you | 165 | you have use for it; the module is called binfmt_misc. If you |
166 | don't know what to answer at this point, say Y. | 166 | don't know what to answer at this point, say Y. |
167 | |||
168 | config COREDUMP | ||
169 | bool "Enable core dump support" if EXPERT | ||
170 | default y | ||
171 | help | ||
172 | This option enables support for performing core dumps. You almost | ||
173 | certainly want to say Y here. Not necessary on systems that never | ||
174 | need debugging or only ever run flawless code. | ||
diff --git a/fs/Makefile b/fs/Makefile index 8938f8250320..1d7af79288a0 100644 --- a/fs/Makefile +++ b/fs/Makefile | |||
@@ -11,7 +11,7 @@ obj-y := open.o read_write.o file_table.o super.o \ | |||
11 | attr.o bad_inode.o file.o filesystems.o namespace.o \ | 11 | attr.o bad_inode.o file.o filesystems.o namespace.o \ |
12 | seq_file.o xattr.o libfs.o fs-writeback.o \ | 12 | seq_file.o xattr.o libfs.o fs-writeback.o \ |
13 | pnode.o drop_caches.o splice.o sync.o utimes.o \ | 13 | pnode.o drop_caches.o splice.o sync.o utimes.o \ |
14 | stack.o fs_struct.o statfs.o coredump.o | 14 | stack.o fs_struct.o statfs.o |
15 | 15 | ||
16 | ifeq ($(CONFIG_BLOCK),y) | 16 | ifeq ($(CONFIG_BLOCK),y) |
17 | obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o | 17 | obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o |
@@ -48,6 +48,7 @@ obj-$(CONFIG_FS_MBCACHE) += mbcache.o | |||
48 | obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o | 48 | obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o |
49 | obj-$(CONFIG_NFS_COMMON) += nfs_common/ | 49 | obj-$(CONFIG_NFS_COMMON) += nfs_common/ |
50 | obj-$(CONFIG_GENERIC_ACL) += generic_acl.o | 50 | obj-$(CONFIG_GENERIC_ACL) += generic_acl.o |
51 | obj-$(CONFIG_COREDUMP) += coredump.o | ||
51 | 52 | ||
52 | obj-$(CONFIG_FHANDLE) += fhandle.o | 53 | obj-$(CONFIG_FHANDLE) += fhandle.o |
53 | 54 | ||
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index d146e181d10d..0e7a6f81ae36 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c | |||
@@ -32,31 +32,8 @@ | |||
32 | 32 | ||
33 | static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs); | 33 | static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs); |
34 | static int load_aout_library(struct file*); | 34 | static int load_aout_library(struct file*); |
35 | static int aout_core_dump(struct coredump_params *cprm); | ||
36 | |||
37 | static struct linux_binfmt aout_format = { | ||
38 | .module = THIS_MODULE, | ||
39 | .load_binary = load_aout_binary, | ||
40 | .load_shlib = load_aout_library, | ||
41 | .core_dump = aout_core_dump, | ||
42 | .min_coredump = PAGE_SIZE | ||
43 | }; | ||
44 | |||
45 | #define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) | ||
46 | |||
47 | static int set_brk(unsigned long start, unsigned long end) | ||
48 | { | ||
49 | start = PAGE_ALIGN(start); | ||
50 | end = PAGE_ALIGN(end); | ||
51 | if (end > start) { | ||
52 | unsigned long addr; | ||
53 | addr = vm_brk(start, end - start); | ||
54 | if (BAD_ADDR(addr)) | ||
55 | return addr; | ||
56 | } | ||
57 | return 0; | ||
58 | } | ||
59 | 35 | ||
36 | #ifdef CONFIG_COREDUMP | ||
60 | /* | 37 | /* |
61 | * Routine writes a core dump image in the current directory. | 38 | * Routine writes a core dump image in the current directory. |
62 | * Currently only a stub-function. | 39 | * Currently only a stub-function. |
@@ -66,7 +43,6 @@ static int set_brk(unsigned long start, unsigned long end) | |||
66 | * field, which also makes sure the core-dumps won't be recursive if the | 43 | * field, which also makes sure the core-dumps won't be recursive if the |
67 | * dumping of the process results in another error.. | 44 | * dumping of the process results in another error.. |
68 | */ | 45 | */ |
69 | |||
70 | static int aout_core_dump(struct coredump_params *cprm) | 46 | static int aout_core_dump(struct coredump_params *cprm) |
71 | { | 47 | { |
72 | struct file *file = cprm->file; | 48 | struct file *file = cprm->file; |
@@ -89,7 +65,7 @@ static int aout_core_dump(struct coredump_params *cprm) | |||
89 | current->flags |= PF_DUMPCORE; | 65 | current->flags |= PF_DUMPCORE; |
90 | strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm)); | 66 | strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm)); |
91 | dump.u_ar0 = offsetof(struct user, regs); | 67 | dump.u_ar0 = offsetof(struct user, regs); |
92 | dump.signal = cprm->signr; | 68 | dump.signal = cprm->siginfo->si_signo; |
93 | aout_dump_thread(cprm->regs, &dump); | 69 | aout_dump_thread(cprm->regs, &dump); |
94 | 70 | ||
95 | /* If the size of the dump file exceeds the rlimit, then see what would happen | 71 | /* If the size of the dump file exceeds the rlimit, then see what would happen |
@@ -135,6 +111,32 @@ end_coredump: | |||
135 | set_fs(fs); | 111 | set_fs(fs); |
136 | return has_dumped; | 112 | return has_dumped; |
137 | } | 113 | } |
114 | #else | ||
115 | #define aout_core_dump NULL | ||
116 | #endif | ||
117 | |||
118 | static struct linux_binfmt aout_format = { | ||
119 | .module = THIS_MODULE, | ||
120 | .load_binary = load_aout_binary, | ||
121 | .load_shlib = load_aout_library, | ||
122 | .core_dump = aout_core_dump, | ||
123 | .min_coredump = PAGE_SIZE | ||
124 | }; | ||
125 | |||
126 | #define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE) | ||
127 | |||
128 | static int set_brk(unsigned long start, unsigned long end) | ||
129 | { | ||
130 | start = PAGE_ALIGN(start); | ||
131 | end = PAGE_ALIGN(end); | ||
132 | if (end > start) { | ||
133 | unsigned long addr; | ||
134 | addr = vm_brk(start, end - start); | ||
135 | if (BAD_ADDR(addr)) | ||
136 | return addr; | ||
137 | } | ||
138 | return 0; | ||
139 | } | ||
138 | 140 | ||
139 | /* | 141 | /* |
140 | * create_aout_tables() parses the env- and arg-strings in new user | 142 | * create_aout_tables() parses the env- and arg-strings in new user |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 0225fddf49b7..28a64e769527 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/compiler.h> | 27 | #include <linux/compiler.h> |
28 | #include <linux/highmem.h> | 28 | #include <linux/highmem.h> |
29 | #include <linux/pagemap.h> | 29 | #include <linux/pagemap.h> |
30 | #include <linux/vmalloc.h> | ||
30 | #include <linux/security.h> | 31 | #include <linux/security.h> |
31 | #include <linux/random.h> | 32 | #include <linux/random.h> |
32 | #include <linux/elf.h> | 33 | #include <linux/elf.h> |
@@ -37,6 +38,13 @@ | |||
37 | #include <asm/page.h> | 38 | #include <asm/page.h> |
38 | #include <asm/exec.h> | 39 | #include <asm/exec.h> |
39 | 40 | ||
41 | #ifndef user_long_t | ||
42 | #define user_long_t long | ||
43 | #endif | ||
44 | #ifndef user_siginfo_t | ||
45 | #define user_siginfo_t siginfo_t | ||
46 | #endif | ||
47 | |||
40 | static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); | 48 | static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); |
41 | static int load_elf_library(struct file *); | 49 | static int load_elf_library(struct file *); |
42 | static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, | 50 | static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, |
@@ -881,7 +889,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
881 | } | 889 | } |
882 | 890 | ||
883 | if (elf_interpreter) { | 891 | if (elf_interpreter) { |
884 | unsigned long uninitialized_var(interp_map_addr); | 892 | unsigned long interp_map_addr = 0; |
885 | 893 | ||
886 | elf_entry = load_elf_interp(&loc->interp_elf_ex, | 894 | elf_entry = load_elf_interp(&loc->interp_elf_ex, |
887 | interpreter, | 895 | interpreter, |
@@ -1372,6 +1380,103 @@ static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm) | |||
1372 | fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); | 1380 | fill_note(note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); |
1373 | } | 1381 | } |
1374 | 1382 | ||
1383 | static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata, | ||
1384 | siginfo_t *siginfo) | ||
1385 | { | ||
1386 | mm_segment_t old_fs = get_fs(); | ||
1387 | set_fs(KERNEL_DS); | ||
1388 | copy_siginfo_to_user((user_siginfo_t __user *) csigdata, siginfo); | ||
1389 | set_fs(old_fs); | ||
1390 | fill_note(note, "CORE", NT_SIGINFO, sizeof(*csigdata), csigdata); | ||
1391 | } | ||
1392 | |||
1393 | #define MAX_FILE_NOTE_SIZE (4*1024*1024) | ||
1394 | /* | ||
1395 | * Format of NT_FILE note: | ||
1396 | * | ||
1397 | * long count -- how many files are mapped | ||
1398 | * long page_size -- units for file_ofs | ||
1399 | * array of [COUNT] elements of | ||
1400 | * long start | ||
1401 | * long end | ||
1402 | * long file_ofs | ||
1403 | * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL... | ||
1404 | */ | ||
1405 | static void fill_files_note(struct memelfnote *note) | ||
1406 | { | ||
1407 | struct vm_area_struct *vma; | ||
1408 | unsigned count, size, names_ofs, remaining, n; | ||
1409 | user_long_t *data; | ||
1410 | user_long_t *start_end_ofs; | ||
1411 | char *name_base, *name_curpos; | ||
1412 | |||
1413 | /* *Estimated* file count and total data size needed */ | ||
1414 | count = current->mm->map_count; | ||
1415 | size = count * 64; | ||
1416 | |||
1417 | names_ofs = (2 + 3 * count) * sizeof(data[0]); | ||
1418 | alloc: | ||
1419 | if (size >= MAX_FILE_NOTE_SIZE) /* paranoia check */ | ||
1420 | goto err; | ||
1421 | size = round_up(size, PAGE_SIZE); | ||
1422 | data = vmalloc(size); | ||
1423 | if (!data) | ||
1424 | goto err; | ||
1425 | |||
1426 | start_end_ofs = data + 2; | ||
1427 | name_base = name_curpos = ((char *)data) + names_ofs; | ||
1428 | remaining = size - names_ofs; | ||
1429 | count = 0; | ||
1430 | for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { | ||
1431 | struct file *file; | ||
1432 | const char *filename; | ||
1433 | |||
1434 | file = vma->vm_file; | ||
1435 | if (!file) | ||
1436 | continue; | ||
1437 | filename = d_path(&file->f_path, name_curpos, remaining); | ||
1438 | if (IS_ERR(filename)) { | ||
1439 | if (PTR_ERR(filename) == -ENAMETOOLONG) { | ||
1440 | vfree(data); | ||
1441 | size = size * 5 / 4; | ||
1442 | goto alloc; | ||
1443 | } | ||
1444 | continue; | ||
1445 | } | ||
1446 | |||
1447 | /* d_path() fills at the end, move name down */ | ||
1448 | /* n = strlen(filename) + 1: */ | ||
1449 | n = (name_curpos + remaining) - filename; | ||
1450 | remaining = filename - name_curpos; | ||
1451 | memmove(name_curpos, filename, n); | ||
1452 | name_curpos += n; | ||
1453 | |||
1454 | *start_end_ofs++ = vma->vm_start; | ||
1455 | *start_end_ofs++ = vma->vm_end; | ||
1456 | *start_end_ofs++ = vma->vm_pgoff; | ||
1457 | count++; | ||
1458 | } | ||
1459 | |||
1460 | /* Now we know exact count of files, can store it */ | ||
1461 | data[0] = count; | ||
1462 | data[1] = PAGE_SIZE; | ||
1463 | /* | ||
1464 | * Count usually is less than current->mm->map_count, | ||
1465 | * we need to move filenames down. | ||
1466 | */ | ||
1467 | n = current->mm->map_count - count; | ||
1468 | if (n != 0) { | ||
1469 | unsigned shift_bytes = n * 3 * sizeof(data[0]); | ||
1470 | memmove(name_base - shift_bytes, name_base, | ||
1471 | name_curpos - name_base); | ||
1472 | name_curpos -= shift_bytes; | ||
1473 | } | ||
1474 | |||
1475 | size = name_curpos - (char *)data; | ||
1476 | fill_note(note, "CORE", NT_FILE, size, data); | ||
1477 | err: ; | ||
1478 | } | ||
1479 | |||
1375 | #ifdef CORE_DUMP_USE_REGSET | 1480 | #ifdef CORE_DUMP_USE_REGSET |
1376 | #include <linux/regset.h> | 1481 | #include <linux/regset.h> |
1377 | 1482 | ||
@@ -1385,7 +1490,10 @@ struct elf_thread_core_info { | |||
1385 | struct elf_note_info { | 1490 | struct elf_note_info { |
1386 | struct elf_thread_core_info *thread; | 1491 | struct elf_thread_core_info *thread; |
1387 | struct memelfnote psinfo; | 1492 | struct memelfnote psinfo; |
1493 | struct memelfnote signote; | ||
1388 | struct memelfnote auxv; | 1494 | struct memelfnote auxv; |
1495 | struct memelfnote files; | ||
1496 | user_siginfo_t csigdata; | ||
1389 | size_t size; | 1497 | size_t size; |
1390 | int thread_notes; | 1498 | int thread_notes; |
1391 | }; | 1499 | }; |
@@ -1480,7 +1588,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, | |||
1480 | 1588 | ||
1481 | static int fill_note_info(struct elfhdr *elf, int phdrs, | 1589 | static int fill_note_info(struct elfhdr *elf, int phdrs, |
1482 | struct elf_note_info *info, | 1590 | struct elf_note_info *info, |
1483 | long signr, struct pt_regs *regs) | 1591 | siginfo_t *siginfo, struct pt_regs *regs) |
1484 | { | 1592 | { |
1485 | struct task_struct *dump_task = current; | 1593 | struct task_struct *dump_task = current; |
1486 | const struct user_regset_view *view = task_user_regset_view(dump_task); | 1594 | const struct user_regset_view *view = task_user_regset_view(dump_task); |
@@ -1550,7 +1658,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
1550 | * Now fill in each thread's information. | 1658 | * Now fill in each thread's information. |
1551 | */ | 1659 | */ |
1552 | for (t = info->thread; t != NULL; t = t->next) | 1660 | for (t = info->thread; t != NULL; t = t->next) |
1553 | if (!fill_thread_core_info(t, view, signr, &info->size)) | 1661 | if (!fill_thread_core_info(t, view, siginfo->si_signo, &info->size)) |
1554 | return 0; | 1662 | return 0; |
1555 | 1663 | ||
1556 | /* | 1664 | /* |
@@ -1559,9 +1667,15 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
1559 | fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); | 1667 | fill_psinfo(psinfo, dump_task->group_leader, dump_task->mm); |
1560 | info->size += notesize(&info->psinfo); | 1668 | info->size += notesize(&info->psinfo); |
1561 | 1669 | ||
1670 | fill_siginfo_note(&info->signote, &info->csigdata, siginfo); | ||
1671 | info->size += notesize(&info->signote); | ||
1672 | |||
1562 | fill_auxv_note(&info->auxv, current->mm); | 1673 | fill_auxv_note(&info->auxv, current->mm); |
1563 | info->size += notesize(&info->auxv); | 1674 | info->size += notesize(&info->auxv); |
1564 | 1675 | ||
1676 | fill_files_note(&info->files); | ||
1677 | info->size += notesize(&info->files); | ||
1678 | |||
1565 | return 1; | 1679 | return 1; |
1566 | } | 1680 | } |
1567 | 1681 | ||
@@ -1588,8 +1702,12 @@ static int write_note_info(struct elf_note_info *info, | |||
1588 | 1702 | ||
1589 | if (first && !writenote(&info->psinfo, file, foffset)) | 1703 | if (first && !writenote(&info->psinfo, file, foffset)) |
1590 | return 0; | 1704 | return 0; |
1705 | if (first && !writenote(&info->signote, file, foffset)) | ||
1706 | return 0; | ||
1591 | if (first && !writenote(&info->auxv, file, foffset)) | 1707 | if (first && !writenote(&info->auxv, file, foffset)) |
1592 | return 0; | 1708 | return 0; |
1709 | if (first && !writenote(&info->files, file, foffset)) | ||
1710 | return 0; | ||
1593 | 1711 | ||
1594 | for (i = 1; i < info->thread_notes; ++i) | 1712 | for (i = 1; i < info->thread_notes; ++i) |
1595 | if (t->notes[i].data && | 1713 | if (t->notes[i].data && |
@@ -1616,6 +1734,7 @@ static void free_note_info(struct elf_note_info *info) | |||
1616 | kfree(t); | 1734 | kfree(t); |
1617 | } | 1735 | } |
1618 | kfree(info->psinfo.data); | 1736 | kfree(info->psinfo.data); |
1737 | vfree(info->files.data); | ||
1619 | } | 1738 | } |
1620 | 1739 | ||
1621 | #else | 1740 | #else |
@@ -1681,6 +1800,7 @@ struct elf_note_info { | |||
1681 | #ifdef ELF_CORE_COPY_XFPREGS | 1800 | #ifdef ELF_CORE_COPY_XFPREGS |
1682 | elf_fpxregset_t *xfpu; | 1801 | elf_fpxregset_t *xfpu; |
1683 | #endif | 1802 | #endif |
1803 | user_siginfo_t csigdata; | ||
1684 | int thread_status_size; | 1804 | int thread_status_size; |
1685 | int numnote; | 1805 | int numnote; |
1686 | }; | 1806 | }; |
@@ -1690,8 +1810,8 @@ static int elf_note_info_init(struct elf_note_info *info) | |||
1690 | memset(info, 0, sizeof(*info)); | 1810 | memset(info, 0, sizeof(*info)); |
1691 | INIT_LIST_HEAD(&info->thread_list); | 1811 | INIT_LIST_HEAD(&info->thread_list); |
1692 | 1812 | ||
1693 | /* Allocate space for six ELF notes */ | 1813 | /* Allocate space for ELF notes */ |
1694 | info->notes = kmalloc(6 * sizeof(struct memelfnote), GFP_KERNEL); | 1814 | info->notes = kmalloc(8 * sizeof(struct memelfnote), GFP_KERNEL); |
1695 | if (!info->notes) | 1815 | if (!info->notes) |
1696 | return 0; | 1816 | return 0; |
1697 | info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL); | 1817 | info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL); |
@@ -1713,14 +1833,14 @@ static int elf_note_info_init(struct elf_note_info *info) | |||
1713 | 1833 | ||
1714 | static int fill_note_info(struct elfhdr *elf, int phdrs, | 1834 | static int fill_note_info(struct elfhdr *elf, int phdrs, |
1715 | struct elf_note_info *info, | 1835 | struct elf_note_info *info, |
1716 | long signr, struct pt_regs *regs) | 1836 | siginfo_t *siginfo, struct pt_regs *regs) |
1717 | { | 1837 | { |
1718 | struct list_head *t; | 1838 | struct list_head *t; |
1719 | 1839 | ||
1720 | if (!elf_note_info_init(info)) | 1840 | if (!elf_note_info_init(info)) |
1721 | return 0; | 1841 | return 0; |
1722 | 1842 | ||
1723 | if (signr) { | 1843 | if (siginfo->si_signo) { |
1724 | struct core_thread *ct; | 1844 | struct core_thread *ct; |
1725 | struct elf_thread_status *ets; | 1845 | struct elf_thread_status *ets; |
1726 | 1846 | ||
@@ -1738,13 +1858,13 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
1738 | int sz; | 1858 | int sz; |
1739 | 1859 | ||
1740 | ets = list_entry(t, struct elf_thread_status, list); | 1860 | ets = list_entry(t, struct elf_thread_status, list); |
1741 | sz = elf_dump_thread_status(signr, ets); | 1861 | sz = elf_dump_thread_status(siginfo->si_signo, ets); |
1742 | info->thread_status_size += sz; | 1862 | info->thread_status_size += sz; |
1743 | } | 1863 | } |
1744 | } | 1864 | } |
1745 | /* now collect the dump for the current */ | 1865 | /* now collect the dump for the current */ |
1746 | memset(info->prstatus, 0, sizeof(*info->prstatus)); | 1866 | memset(info->prstatus, 0, sizeof(*info->prstatus)); |
1747 | fill_prstatus(info->prstatus, current, signr); | 1867 | fill_prstatus(info->prstatus, current, siginfo->si_signo); |
1748 | elf_core_copy_regs(&info->prstatus->pr_reg, regs); | 1868 | elf_core_copy_regs(&info->prstatus->pr_reg, regs); |
1749 | 1869 | ||
1750 | /* Set up header */ | 1870 | /* Set up header */ |
@@ -1761,9 +1881,11 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
1761 | fill_note(info->notes + 1, "CORE", NT_PRPSINFO, | 1881 | fill_note(info->notes + 1, "CORE", NT_PRPSINFO, |
1762 | sizeof(*info->psinfo), info->psinfo); | 1882 | sizeof(*info->psinfo), info->psinfo); |
1763 | 1883 | ||
1764 | info->numnote = 2; | 1884 | fill_siginfo_note(info->notes + 2, &info->csigdata, siginfo); |
1885 | fill_auxv_note(info->notes + 3, current->mm); | ||
1886 | fill_files_note(info->notes + 4); | ||
1765 | 1887 | ||
1766 | fill_auxv_note(&info->notes[info->numnote++], current->mm); | 1888 | info->numnote = 5; |
1767 | 1889 | ||
1768 | /* Try to dump the FPU. */ | 1890 | /* Try to dump the FPU. */ |
1769 | info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, | 1891 | info->prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, |
@@ -1825,6 +1947,9 @@ static void free_note_info(struct elf_note_info *info) | |||
1825 | kfree(list_entry(tmp, struct elf_thread_status, list)); | 1947 | kfree(list_entry(tmp, struct elf_thread_status, list)); |
1826 | } | 1948 | } |
1827 | 1949 | ||
1950 | /* Free data allocated by fill_files_note(): */ | ||
1951 | vfree(info->notes[4].data); | ||
1952 | |||
1828 | kfree(info->prstatus); | 1953 | kfree(info->prstatus); |
1829 | kfree(info->psinfo); | 1954 | kfree(info->psinfo); |
1830 | kfree(info->notes); | 1955 | kfree(info->notes); |
@@ -1951,7 +2076,7 @@ static int elf_core_dump(struct coredump_params *cprm) | |||
1951 | * Collect all the non-memory information about the process for the | 2076 | * Collect all the non-memory information about the process for the |
1952 | * notes. This also sets up the file header. | 2077 | * notes. This also sets up the file header. |
1953 | */ | 2078 | */ |
1954 | if (!fill_note_info(elf, e_phnum, &info, cprm->signr, cprm->regs)) | 2079 | if (!fill_note_info(elf, e_phnum, &info, cprm->siginfo, cprm->regs)) |
1955 | goto cleanup; | 2080 | goto cleanup; |
1956 | 2081 | ||
1957 | has_dumped = 1; | 2082 | has_dumped = 1; |
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 3d77cf81ba3c..08d812b32282 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
@@ -1642,7 +1642,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) | |||
1642 | goto cleanup; | 1642 | goto cleanup; |
1643 | #endif | 1643 | #endif |
1644 | 1644 | ||
1645 | if (cprm->signr) { | 1645 | if (cprm->siginfo->si_signo) { |
1646 | struct core_thread *ct; | 1646 | struct core_thread *ct; |
1647 | struct elf_thread_status *tmp; | 1647 | struct elf_thread_status *tmp; |
1648 | 1648 | ||
@@ -1661,13 +1661,13 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) | |||
1661 | int sz; | 1661 | int sz; |
1662 | 1662 | ||
1663 | tmp = list_entry(t, struct elf_thread_status, list); | 1663 | tmp = list_entry(t, struct elf_thread_status, list); |
1664 | sz = elf_dump_thread_status(cprm->signr, tmp); | 1664 | sz = elf_dump_thread_status(cprm->siginfo->si_signo, tmp); |
1665 | thread_status_size += sz; | 1665 | thread_status_size += sz; |
1666 | } | 1666 | } |
1667 | } | 1667 | } |
1668 | 1668 | ||
1669 | /* now collect the dump for the current */ | 1669 | /* now collect the dump for the current */ |
1670 | fill_prstatus(prstatus, current, cprm->signr); | 1670 | fill_prstatus(prstatus, current, cprm->siginfo->si_signo); |
1671 | elf_core_copy_regs(&prstatus->pr_reg, cprm->regs); | 1671 | elf_core_copy_regs(&prstatus->pr_reg, cprm->regs); |
1672 | 1672 | ||
1673 | segs = current->mm->map_count; | 1673 | segs = current->mm->map_count; |
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 178cb70acc26..e280352b28f9 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c | |||
@@ -107,7 +107,7 @@ static struct linux_binfmt flat_format = { | |||
107 | static int flat_core_dump(struct coredump_params *cprm) | 107 | static int flat_core_dump(struct coredump_params *cprm) |
108 | { | 108 | { |
109 | printk("Process %s:%d received signr %d and should have core dumped\n", | 109 | printk("Process %s:%d received signr %d and should have core dumped\n", |
110 | current->comm, current->pid, (int) cprm->signr); | 110 | current->comm, current->pid, (int) cprm->siginfo->si_signo); |
111 | return(1); | 111 | return(1); |
112 | } | 112 | } |
113 | 113 | ||
diff --git a/fs/compat_binfmt_elf.c b/fs/compat_binfmt_elf.c index 112e45a17e99..a81147e2e4ef 100644 --- a/fs/compat_binfmt_elf.c +++ b/fs/compat_binfmt_elf.c | |||
@@ -38,6 +38,13 @@ | |||
38 | #define elf_addr_t Elf32_Addr | 38 | #define elf_addr_t Elf32_Addr |
39 | 39 | ||
40 | /* | 40 | /* |
41 | * Some data types as stored in coredump. | ||
42 | */ | ||
43 | #define user_long_t compat_long_t | ||
44 | #define user_siginfo_t compat_siginfo_t | ||
45 | #define copy_siginfo_to_user copy_siginfo_to_user32 | ||
46 | |||
47 | /* | ||
41 | * The machine-dependent core note format types are defined in elfcore-compat.h, | 48 | * The machine-dependent core note format types are defined in elfcore-compat.h, |
42 | * which requires asm/elf.h to define compat_elf_gregset_t et al. | 49 | * which requires asm/elf.h to define compat_elf_gregset_t et al. |
43 | */ | 50 | */ |
diff --git a/fs/coredump.c b/fs/coredump.c index f045bbad6822..fd37facac8dc 100644 --- a/fs/coredump.c +++ b/fs/coredump.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/key.h> | 14 | #include <linux/key.h> |
15 | #include <linux/personality.h> | 15 | #include <linux/personality.h> |
16 | #include <linux/binfmts.h> | 16 | #include <linux/binfmts.h> |
17 | #include <linux/coredump.h> | ||
17 | #include <linux/utsname.h> | 18 | #include <linux/utsname.h> |
18 | #include <linux/pid_namespace.h> | 19 | #include <linux/pid_namespace.h> |
19 | #include <linux/module.h> | 20 | #include <linux/module.h> |
@@ -39,6 +40,7 @@ | |||
39 | 40 | ||
40 | #include <trace/events/task.h> | 41 | #include <trace/events/task.h> |
41 | #include "internal.h" | 42 | #include "internal.h" |
43 | #include "coredump.h" | ||
42 | 44 | ||
43 | #include <trace/events/sched.h> | 45 | #include <trace/events/sched.h> |
44 | 46 | ||
@@ -147,7 +149,7 @@ put_exe_file: | |||
147 | * name into corename, which must have space for at least | 149 | * name into corename, which must have space for at least |
148 | * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator. | 150 | * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator. |
149 | */ | 151 | */ |
150 | static int format_corename(struct core_name *cn, long signr) | 152 | static int format_corename(struct core_name *cn, struct coredump_params *cprm) |
151 | { | 153 | { |
152 | const struct cred *cred = current_cred(); | 154 | const struct cred *cred = current_cred(); |
153 | const char *pat_ptr = core_pattern; | 155 | const char *pat_ptr = core_pattern; |
@@ -192,9 +194,13 @@ static int format_corename(struct core_name *cn, long signr) | |||
192 | case 'g': | 194 | case 'g': |
193 | err = cn_printf(cn, "%d", cred->gid); | 195 | err = cn_printf(cn, "%d", cred->gid); |
194 | break; | 196 | break; |
197 | case 'd': | ||
198 | err = cn_printf(cn, "%d", | ||
199 | __get_dumpable(cprm->mm_flags)); | ||
200 | break; | ||
195 | /* signal that caused the coredump */ | 201 | /* signal that caused the coredump */ |
196 | case 's': | 202 | case 's': |
197 | err = cn_printf(cn, "%ld", signr); | 203 | err = cn_printf(cn, "%ld", cprm->siginfo->si_signo); |
198 | break; | 204 | break; |
199 | /* UNIX time of coredump */ | 205 | /* UNIX time of coredump */ |
200 | case 't': { | 206 | case 't': { |
@@ -451,7 +457,7 @@ static int umh_pipe_setup(struct subprocess_info *info, struct cred *new) | |||
451 | return 0; | 457 | return 0; |
452 | } | 458 | } |
453 | 459 | ||
454 | void do_coredump(long signr, int exit_code, struct pt_regs *regs) | 460 | void do_coredump(siginfo_t *siginfo, struct pt_regs *regs) |
455 | { | 461 | { |
456 | struct core_state core_state; | 462 | struct core_state core_state; |
457 | struct core_name cn; | 463 | struct core_name cn; |
@@ -466,7 +472,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
466 | bool need_nonrelative = false; | 472 | bool need_nonrelative = false; |
467 | static atomic_t core_dump_count = ATOMIC_INIT(0); | 473 | static atomic_t core_dump_count = ATOMIC_INIT(0); |
468 | struct coredump_params cprm = { | 474 | struct coredump_params cprm = { |
469 | .signr = signr, | 475 | .siginfo = siginfo, |
470 | .regs = regs, | 476 | .regs = regs, |
471 | .limit = rlimit(RLIMIT_CORE), | 477 | .limit = rlimit(RLIMIT_CORE), |
472 | /* | 478 | /* |
@@ -477,7 +483,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
477 | .mm_flags = mm->flags, | 483 | .mm_flags = mm->flags, |
478 | }; | 484 | }; |
479 | 485 | ||
480 | audit_core_dumps(signr); | 486 | audit_core_dumps(siginfo->si_signo); |
481 | 487 | ||
482 | binfmt = mm->binfmt; | 488 | binfmt = mm->binfmt; |
483 | if (!binfmt || !binfmt->core_dump) | 489 | if (!binfmt || !binfmt->core_dump) |
@@ -501,7 +507,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
501 | need_nonrelative = true; | 507 | need_nonrelative = true; |
502 | } | 508 | } |
503 | 509 | ||
504 | retval = coredump_wait(exit_code, &core_state); | 510 | retval = coredump_wait(siginfo->si_signo, &core_state); |
505 | if (retval < 0) | 511 | if (retval < 0) |
506 | goto fail_creds; | 512 | goto fail_creds; |
507 | 513 | ||
@@ -513,7 +519,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
513 | */ | 519 | */ |
514 | clear_thread_flag(TIF_SIGPENDING); | 520 | clear_thread_flag(TIF_SIGPENDING); |
515 | 521 | ||
516 | ispipe = format_corename(&cn, signr); | 522 | ispipe = format_corename(&cn, &cprm); |
517 | 523 | ||
518 | if (ispipe) { | 524 | if (ispipe) { |
519 | int dump_count; | 525 | int dump_count; |
diff --git a/fs/coredump.h b/fs/coredump.h new file mode 100644 index 000000000000..e39ff072110d --- /dev/null +++ b/fs/coredump.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef _FS_COREDUMP_H | ||
2 | #define _FS_COREDUMP_H | ||
3 | |||
4 | extern int __get_dumpable(unsigned long mm_flags); | ||
5 | |||
6 | #endif | ||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index cd96649bfe62..da72250ddc1c 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
@@ -346,7 +346,7 @@ static inline struct epitem *ep_item_from_epqueue(poll_table *p) | |||
346 | /* Tells if the epoll_ctl(2) operation needs an event copy from userspace */ | 346 | /* Tells if the epoll_ctl(2) operation needs an event copy from userspace */ |
347 | static inline int ep_op_has_event(int op) | 347 | static inline int ep_op_has_event(int op) |
348 | { | 348 | { |
349 | return op != EPOLL_CTL_DEL; | 349 | return op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD; |
350 | } | 350 | } |
351 | 351 | ||
352 | /* Initialize the poll safe wake up structure */ | 352 | /* Initialize the poll safe wake up structure */ |
@@ -676,6 +676,34 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi) | |||
676 | return 0; | 676 | return 0; |
677 | } | 677 | } |
678 | 678 | ||
679 | /* | ||
680 | * Disables a "struct epitem" in the eventpoll set. Returns -EBUSY if the item | ||
681 | * had no event flags set, indicating that another thread may be currently | ||
682 | * handling that item's events (in the case that EPOLLONESHOT was being | ||
683 | * used). Otherwise a zero result indicates that the item has been disabled | ||
684 | * from receiving events. A disabled item may be re-enabled via | ||
685 | * EPOLL_CTL_MOD. Must be called with "mtx" held. | ||
686 | */ | ||
687 | static int ep_disable(struct eventpoll *ep, struct epitem *epi) | ||
688 | { | ||
689 | int result = 0; | ||
690 | unsigned long flags; | ||
691 | |||
692 | spin_lock_irqsave(&ep->lock, flags); | ||
693 | if (epi->event.events & ~EP_PRIVATE_BITS) { | ||
694 | if (ep_is_linked(&epi->rdllink)) | ||
695 | list_del_init(&epi->rdllink); | ||
696 | /* Ensure ep_poll_callback will not add epi back onto ready | ||
697 | list: */ | ||
698 | epi->event.events &= EP_PRIVATE_BITS; | ||
699 | } | ||
700 | else | ||
701 | result = -EBUSY; | ||
702 | spin_unlock_irqrestore(&ep->lock, flags); | ||
703 | |||
704 | return result; | ||
705 | } | ||
706 | |||
679 | static void ep_free(struct eventpoll *ep) | 707 | static void ep_free(struct eventpoll *ep) |
680 | { | 708 | { |
681 | struct rb_node *rbp; | 709 | struct rb_node *rbp; |
@@ -1020,8 +1048,6 @@ static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi) | |||
1020 | rb_insert_color(&epi->rbn, &ep->rbr); | 1048 | rb_insert_color(&epi->rbn, &ep->rbr); |
1021 | } | 1049 | } |
1022 | 1050 | ||
1023 | |||
1024 | |||
1025 | #define PATH_ARR_SIZE 5 | 1051 | #define PATH_ARR_SIZE 5 |
1026 | /* | 1052 | /* |
1027 | * These are the number paths of length 1 to 5, that we are allowing to emanate | 1053 | * These are the number paths of length 1 to 5, that we are allowing to emanate |
@@ -1787,6 +1813,12 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, | |||
1787 | } else | 1813 | } else |
1788 | error = -ENOENT; | 1814 | error = -ENOENT; |
1789 | break; | 1815 | break; |
1816 | case EPOLL_CTL_DISABLE: | ||
1817 | if (epi) | ||
1818 | error = ep_disable(ep, epi); | ||
1819 | else | ||
1820 | error = -ENOENT; | ||
1821 | break; | ||
1790 | } | 1822 | } |
1791 | mutex_unlock(&ep->mtx); | 1823 | mutex_unlock(&ep->mtx); |
1792 | 1824 | ||
@@ -63,6 +63,7 @@ | |||
63 | 63 | ||
64 | #include <trace/events/task.h> | 64 | #include <trace/events/task.h> |
65 | #include "internal.h" | 65 | #include "internal.h" |
66 | #include "coredump.h" | ||
66 | 67 | ||
67 | #include <trace/events/sched.h> | 68 | #include <trace/events/sched.h> |
68 | 69 | ||
@@ -1096,7 +1097,7 @@ void setup_new_exec(struct linux_binprm * bprm) | |||
1096 | current->sas_ss_sp = current->sas_ss_size = 0; | 1097 | current->sas_ss_sp = current->sas_ss_size = 0; |
1097 | 1098 | ||
1098 | if (uid_eq(current_euid(), current_uid()) && gid_eq(current_egid(), current_gid())) | 1099 | if (uid_eq(current_euid(), current_uid()) && gid_eq(current_egid(), current_gid())) |
1099 | set_dumpable(current->mm, 1); | 1100 | set_dumpable(current->mm, SUID_DUMPABLE_ENABLED); |
1100 | else | 1101 | else |
1101 | set_dumpable(current->mm, suid_dumpable); | 1102 | set_dumpable(current->mm, suid_dumpable); |
1102 | 1103 | ||
diff --git a/fs/fat/Makefile b/fs/fat/Makefile index e06190322c1c..964b634f6667 100644 --- a/fs/fat/Makefile +++ b/fs/fat/Makefile | |||
@@ -6,6 +6,6 @@ obj-$(CONFIG_FAT_FS) += fat.o | |||
6 | obj-$(CONFIG_VFAT_FS) += vfat.o | 6 | obj-$(CONFIG_VFAT_FS) += vfat.o |
7 | obj-$(CONFIG_MSDOS_FS) += msdos.o | 7 | obj-$(CONFIG_MSDOS_FS) += msdos.o |
8 | 8 | ||
9 | fat-y := cache.o dir.o fatent.o file.o inode.o misc.o | 9 | fat-y := cache.o dir.o fatent.o file.o inode.o misc.o nfs.o |
10 | vfat-y := namei_vfat.o | 10 | vfat-y := namei_vfat.o |
11 | msdos-y := namei_msdos.o | 11 | msdos-y := namei_msdos.o |
diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 1cc7038e273d..91ad9e1c9441 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c | |||
@@ -190,7 +190,8 @@ static void __fat_cache_inval_inode(struct inode *inode) | |||
190 | struct fat_cache *cache; | 190 | struct fat_cache *cache; |
191 | 191 | ||
192 | while (!list_empty(&i->cache_lru)) { | 192 | while (!list_empty(&i->cache_lru)) { |
193 | cache = list_entry(i->cache_lru.next, struct fat_cache, cache_list); | 193 | cache = list_entry(i->cache_lru.next, |
194 | struct fat_cache, cache_list); | ||
194 | list_del_init(&cache->cache_list); | 195 | list_del_init(&cache->cache_list); |
195 | i->nr_caches--; | 196 | i->nr_caches--; |
196 | fat_cache_free(cache); | 197 | fat_cache_free(cache); |
@@ -261,9 +262,10 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) | |||
261 | if (nr < 0) | 262 | if (nr < 0) |
262 | goto out; | 263 | goto out; |
263 | else if (nr == FAT_ENT_FREE) { | 264 | else if (nr == FAT_ENT_FREE) { |
264 | fat_fs_error_ratelimit(sb, "%s: invalid cluster chain" | 265 | fat_fs_error_ratelimit(sb, |
265 | " (i_pos %lld)", __func__, | 266 | "%s: invalid cluster chain (i_pos %lld)", |
266 | MSDOS_I(inode)->i_pos); | 267 | __func__, |
268 | MSDOS_I(inode)->i_pos); | ||
267 | nr = -EIO; | 269 | nr = -EIO; |
268 | goto out; | 270 | goto out; |
269 | } else if (nr == FAT_ENT_EOF) { | 271 | } else if (nr == FAT_ENT_EOF) { |
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index dc49ed2cbffa..bca6d0a1255e 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include <linux/time.h> | 18 | #include <linux/time.h> |
19 | #include <linux/buffer_head.h> | 19 | #include <linux/buffer_head.h> |
20 | #include <linux/compat.h> | 20 | #include <linux/compat.h> |
21 | #include <asm/uaccess.h> | 21 | #include <linux/uaccess.h> |
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include "fat.h" | 23 | #include "fat.h" |
24 | 24 | ||
@@ -123,7 +123,8 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos, | |||
123 | { | 123 | { |
124 | /* Fast stuff first */ | 124 | /* Fast stuff first */ |
125 | if (*bh && *de && | 125 | if (*bh && *de && |
126 | (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) { | 126 | (*de - (struct msdos_dir_entry *)(*bh)->b_data) < |
127 | MSDOS_SB(dir->i_sb)->dir_per_block - 1) { | ||
127 | *pos += sizeof(struct msdos_dir_entry); | 128 | *pos += sizeof(struct msdos_dir_entry); |
128 | (*de)++; | 129 | (*de)++; |
129 | return 0; | 130 | return 0; |
@@ -155,7 +156,8 @@ static int uni16_to_x8(struct super_block *sb, unsigned char *ascii, | |||
155 | 156 | ||
156 | while (*ip && ((len - NLS_MAX_CHARSET_SIZE) > 0)) { | 157 | while (*ip && ((len - NLS_MAX_CHARSET_SIZE) > 0)) { |
157 | ec = *ip++; | 158 | ec = *ip++; |
158 | if ((charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE)) > 0) { | 159 | charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE); |
160 | if (charlen > 0) { | ||
159 | op += charlen; | 161 | op += charlen; |
160 | len -= charlen; | 162 | len -= charlen; |
161 | } else { | 163 | } else { |
@@ -172,12 +174,12 @@ static int uni16_to_x8(struct super_block *sb, unsigned char *ascii, | |||
172 | } | 174 | } |
173 | 175 | ||
174 | if (unlikely(*ip)) { | 176 | if (unlikely(*ip)) { |
175 | fat_msg(sb, KERN_WARNING, "filename was truncated while " | 177 | fat_msg(sb, KERN_WARNING, |
176 | "converting."); | 178 | "filename was truncated while converting."); |
177 | } | 179 | } |
178 | 180 | ||
179 | *op = 0; | 181 | *op = 0; |
180 | return (op - ascii); | 182 | return op - ascii; |
181 | } | 183 | } |
182 | 184 | ||
183 | static inline int fat_uni_to_x8(struct super_block *sb, const wchar_t *uni, | 185 | static inline int fat_uni_to_x8(struct super_block *sb, const wchar_t *uni, |
@@ -205,7 +207,8 @@ fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni) | |||
205 | } | 207 | } |
206 | 208 | ||
207 | static inline int | 209 | static inline int |
208 | fat_short2lower_uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni) | 210 | fat_short2lower_uni(struct nls_table *t, unsigned char *c, |
211 | int clen, wchar_t *uni) | ||
209 | { | 212 | { |
210 | int charlen; | 213 | int charlen; |
211 | wchar_t wc; | 214 | wchar_t wc; |
@@ -220,7 +223,8 @@ fat_short2lower_uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *un | |||
220 | if (!nc) | 223 | if (!nc) |
221 | nc = *c; | 224 | nc = *c; |
222 | 225 | ||
223 | if ( (charlen = t->char2uni(&nc, 1, uni)) < 0) { | 226 | charlen = t->char2uni(&nc, 1, uni); |
227 | if (charlen < 0) { | ||
224 | *uni = 0x003f; /* a question mark */ | 228 | *uni = 0x003f; /* a question mark */ |
225 | charlen = 1; | 229 | charlen = 1; |
226 | } | 230 | } |
@@ -537,7 +541,6 @@ end_of_dir: | |||
537 | 541 | ||
538 | return err; | 542 | return err; |
539 | } | 543 | } |
540 | |||
541 | EXPORT_SYMBOL_GPL(fat_search_long); | 544 | EXPORT_SYMBOL_GPL(fat_search_long); |
542 | 545 | ||
543 | struct fat_ioctl_filldir_callback { | 546 | struct fat_ioctl_filldir_callback { |
@@ -574,7 +577,8 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent, | |||
574 | /* Fake . and .. for the root directory. */ | 577 | /* Fake . and .. for the root directory. */ |
575 | if (inode->i_ino == MSDOS_ROOT_INO) { | 578 | if (inode->i_ino == MSDOS_ROOT_INO) { |
576 | while (cpos < 2) { | 579 | while (cpos < 2) { |
577 | if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO, DT_DIR) < 0) | 580 | if (filldir(dirent, "..", cpos+1, cpos, |
581 | MSDOS_ROOT_INO, DT_DIR) < 0) | ||
578 | goto out; | 582 | goto out; |
579 | cpos++; | 583 | cpos++; |
580 | filp->f_pos++; | 584 | filp->f_pos++; |
@@ -872,25 +876,26 @@ static int fat_get_short_entry(struct inode *dir, loff_t *pos, | |||
872 | } | 876 | } |
873 | 877 | ||
874 | /* | 878 | /* |
875 | * The ".." entry can not provide the "struct fat_slot_info" informations | 879 | * The ".." entry can not provide the "struct fat_slot_info" information |
876 | * for inode. So, this function provide the some informations only. | 880 | * for inode, nor a usable i_pos. So, this function provides some information |
881 | * only. | ||
882 | * | ||
883 | * Since this function walks through the on-disk inodes within a directory, | ||
884 | * callers are responsible for taking any locks necessary to prevent the | ||
885 | * directory from changing. | ||
877 | */ | 886 | */ |
878 | int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh, | 887 | int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh, |
879 | struct msdos_dir_entry **de, loff_t *i_pos) | 888 | struct msdos_dir_entry **de) |
880 | { | 889 | { |
881 | loff_t offset; | 890 | loff_t offset = 0; |
882 | 891 | ||
883 | offset = 0; | 892 | *de = NULL; |
884 | *bh = NULL; | ||
885 | while (fat_get_short_entry(dir, &offset, bh, de) >= 0) { | 893 | while (fat_get_short_entry(dir, &offset, bh, de) >= 0) { |
886 | if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME)) { | 894 | if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME)) |
887 | *i_pos = fat_make_i_pos(dir->i_sb, *bh, *de); | ||
888 | return 0; | 895 | return 0; |
889 | } | ||
890 | } | 896 | } |
891 | return -ENOENT; | 897 | return -ENOENT; |
892 | } | 898 | } |
893 | |||
894 | EXPORT_SYMBOL_GPL(fat_get_dotdot_entry); | 899 | EXPORT_SYMBOL_GPL(fat_get_dotdot_entry); |
895 | 900 | ||
896 | /* See if directory is empty */ | 901 | /* See if directory is empty */ |
@@ -913,7 +918,6 @@ int fat_dir_empty(struct inode *dir) | |||
913 | brelse(bh); | 918 | brelse(bh); |
914 | return result; | 919 | return result; |
915 | } | 920 | } |
916 | |||
917 | EXPORT_SYMBOL_GPL(fat_dir_empty); | 921 | EXPORT_SYMBOL_GPL(fat_dir_empty); |
918 | 922 | ||
919 | /* | 923 | /* |
@@ -959,7 +963,6 @@ int fat_scan(struct inode *dir, const unsigned char *name, | |||
959 | } | 963 | } |
960 | return -ENOENT; | 964 | return -ENOENT; |
961 | } | 965 | } |
962 | |||
963 | EXPORT_SYMBOL_GPL(fat_scan); | 966 | EXPORT_SYMBOL_GPL(fat_scan); |
964 | 967 | ||
965 | static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots) | 968 | static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots) |
@@ -1047,7 +1050,6 @@ int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo) | |||
1047 | 1050 | ||
1048 | return 0; | 1051 | return 0; |
1049 | } | 1052 | } |
1050 | |||
1051 | EXPORT_SYMBOL_GPL(fat_remove_entries); | 1053 | EXPORT_SYMBOL_GPL(fat_remove_entries); |
1052 | 1054 | ||
1053 | static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used, | 1055 | static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used, |
@@ -1141,10 +1143,8 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts) | |||
1141 | de[0].ctime_cs = de[1].ctime_cs = 0; | 1143 | de[0].ctime_cs = de[1].ctime_cs = 0; |
1142 | de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0; | 1144 | de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0; |
1143 | } | 1145 | } |
1144 | de[0].start = cpu_to_le16(cluster); | 1146 | fat_set_start(&de[0], cluster); |
1145 | de[0].starthi = cpu_to_le16(cluster >> 16); | 1147 | fat_set_start(&de[1], MSDOS_I(dir)->i_logstart); |
1146 | de[1].start = cpu_to_le16(MSDOS_I(dir)->i_logstart); | ||
1147 | de[1].starthi = cpu_to_le16(MSDOS_I(dir)->i_logstart >> 16); | ||
1148 | de[0].size = de[1].size = 0; | 1148 | de[0].size = de[1].size = 0; |
1149 | memset(de + 2, 0, sb->s_blocksize - 2 * sizeof(*de)); | 1149 | memset(de + 2, 0, sb->s_blocksize - 2 * sizeof(*de)); |
1150 | set_buffer_uptodate(bhs[0]); | 1150 | set_buffer_uptodate(bhs[0]); |
@@ -1161,7 +1161,6 @@ error_free: | |||
1161 | error: | 1161 | error: |
1162 | return err; | 1162 | return err; |
1163 | } | 1163 | } |
1164 | |||
1165 | EXPORT_SYMBOL_GPL(fat_alloc_new_dir); | 1164 | EXPORT_SYMBOL_GPL(fat_alloc_new_dir); |
1166 | 1165 | ||
1167 | static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots, | 1166 | static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots, |
@@ -1377,5 +1376,4 @@ error_remove: | |||
1377 | __fat_remove_entries(dir, pos, free_slots); | 1376 | __fat_remove_entries(dir, pos, free_slots); |
1378 | return err; | 1377 | return err; |
1379 | } | 1378 | } |
1380 | |||
1381 | EXPORT_SYMBOL_GPL(fat_add_entries); | 1379 | EXPORT_SYMBOL_GPL(fat_add_entries); |
diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 7d8e0dcac5d5..ca7e8f8bad7c 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/string.h> | 5 | #include <linux/string.h> |
6 | #include <linux/nls.h> | 6 | #include <linux/nls.h> |
7 | #include <linux/fs.h> | 7 | #include <linux/fs.h> |
8 | #include <linux/hash.h> | ||
8 | #include <linux/mutex.h> | 9 | #include <linux/mutex.h> |
9 | #include <linux/ratelimit.h> | 10 | #include <linux/ratelimit.h> |
10 | #include <linux/msdos_fs.h> | 11 | #include <linux/msdos_fs.h> |
@@ -27,26 +28,27 @@ struct fat_mount_options { | |||
27 | kgid_t fs_gid; | 28 | kgid_t fs_gid; |
28 | unsigned short fs_fmask; | 29 | unsigned short fs_fmask; |
29 | unsigned short fs_dmask; | 30 | unsigned short fs_dmask; |
30 | unsigned short codepage; /* Codepage for shortname conversions */ | 31 | unsigned short codepage; /* Codepage for shortname conversions */ |
31 | char *iocharset; /* Charset used for filename input/display */ | 32 | char *iocharset; /* Charset used for filename input/display */ |
32 | unsigned short shortname; /* flags for shortname display/create rule */ | 33 | unsigned short shortname; /* flags for shortname display/create rule */ |
33 | unsigned char name_check; /* r = relaxed, n = normal, s = strict */ | 34 | unsigned char name_check; /* r = relaxed, n = normal, s = strict */ |
34 | unsigned char errors; /* On error: continue, panic, remount-ro */ | 35 | unsigned char errors; /* On error: continue, panic, remount-ro */ |
35 | unsigned short allow_utime;/* permission for setting the [am]time */ | 36 | unsigned short allow_utime;/* permission for setting the [am]time */ |
36 | unsigned quiet:1, /* set = fake successful chmods and chowns */ | 37 | unsigned quiet:1, /* set = fake successful chmods and chowns */ |
37 | showexec:1, /* set = only set x bit for com/exe/bat */ | 38 | showexec:1, /* set = only set x bit for com/exe/bat */ |
38 | sys_immutable:1, /* set = system files are immutable */ | 39 | sys_immutable:1, /* set = system files are immutable */ |
39 | dotsOK:1, /* set = hidden and system files are named '.filename' */ | 40 | dotsOK:1, /* set = hidden and system files are named '.filename' */ |
40 | isvfat:1, /* 0=no vfat long filename support, 1=vfat support */ | 41 | isvfat:1, /* 0=no vfat long filename support, 1=vfat support */ |
41 | utf8:1, /* Use of UTF-8 character set (Default) */ | 42 | utf8:1, /* Use of UTF-8 character set (Default) */ |
42 | unicode_xlate:1, /* create escape sequences for unhandled Unicode */ | 43 | unicode_xlate:1, /* create escape sequences for unhandled Unicode */ |
43 | numtail:1, /* Does first alias have a numeric '~1' type tail? */ | 44 | numtail:1, /* Does first alias have a numeric '~1' type tail? */ |
44 | flush:1, /* write things quickly */ | 45 | flush:1, /* write things quickly */ |
45 | nocase:1, /* Does this need case conversion? 0=need case conversion*/ | 46 | nocase:1, /* Does this need case conversion? 0=need case conversion*/ |
46 | usefree:1, /* Use free_clusters for FAT32 */ | 47 | usefree:1, /* Use free_clusters for FAT32 */ |
47 | tz_utc:1, /* Filesystem timestamps are in UTC */ | 48 | tz_utc:1, /* Filesystem timestamps are in UTC */ |
48 | rodir:1, /* allow ATTR_RO for directory */ | 49 | rodir:1, /* allow ATTR_RO for directory */ |
49 | discard:1; /* Issue discard requests on deletions */ | 50 | discard:1, /* Issue discard requests on deletions */ |
51 | nfs:1; /* Do extra work needed for NFS export */ | ||
50 | }; | 52 | }; |
51 | 53 | ||
52 | #define FAT_HASH_BITS 8 | 54 | #define FAT_HASH_BITS 8 |
@@ -56,28 +58,28 @@ struct fat_mount_options { | |||
56 | * MS-DOS file system in-core superblock data | 58 | * MS-DOS file system in-core superblock data |
57 | */ | 59 | */ |
58 | struct msdos_sb_info { | 60 | struct msdos_sb_info { |
59 | unsigned short sec_per_clus; /* sectors/cluster */ | 61 | unsigned short sec_per_clus; /* sectors/cluster */ |
60 | unsigned short cluster_bits; /* log2(cluster_size) */ | 62 | unsigned short cluster_bits; /* log2(cluster_size) */ |
61 | unsigned int cluster_size; /* cluster size */ | 63 | unsigned int cluster_size; /* cluster size */ |
62 | unsigned char fats,fat_bits; /* number of FATs, FAT bits (12 or 16) */ | 64 | unsigned char fats, fat_bits; /* number of FATs, FAT bits (12 or 16) */ |
63 | unsigned short fat_start; | 65 | unsigned short fat_start; |
64 | unsigned long fat_length; /* FAT start & length (sec.) */ | 66 | unsigned long fat_length; /* FAT start & length (sec.) */ |
65 | unsigned long dir_start; | 67 | unsigned long dir_start; |
66 | unsigned short dir_entries; /* root dir start & entries */ | 68 | unsigned short dir_entries; /* root dir start & entries */ |
67 | unsigned long data_start; /* first data sector */ | 69 | unsigned long data_start; /* first data sector */ |
68 | unsigned long max_cluster; /* maximum cluster number */ | 70 | unsigned long max_cluster; /* maximum cluster number */ |
69 | unsigned long root_cluster; /* first cluster of the root directory */ | 71 | unsigned long root_cluster; /* first cluster of the root directory */ |
70 | unsigned long fsinfo_sector; /* sector number of FAT32 fsinfo */ | 72 | unsigned long fsinfo_sector; /* sector number of FAT32 fsinfo */ |
71 | struct mutex fat_lock; | 73 | struct mutex fat_lock; |
72 | unsigned int prev_free; /* previously allocated cluster number */ | 74 | unsigned int prev_free; /* previously allocated cluster number */ |
73 | unsigned int free_clusters; /* -1 if undefined */ | 75 | unsigned int free_clusters; /* -1 if undefined */ |
74 | unsigned int free_clus_valid; /* is free_clusters valid? */ | 76 | unsigned int free_clus_valid; /* is free_clusters valid? */ |
75 | struct fat_mount_options options; | 77 | struct fat_mount_options options; |
76 | struct nls_table *nls_disk; /* Codepage used on disk */ | 78 | struct nls_table *nls_disk; /* Codepage used on disk */ |
77 | struct nls_table *nls_io; /* Charset used for input and display */ | 79 | struct nls_table *nls_io; /* Charset used for input and display */ |
78 | const void *dir_ops; /* Opaque; default directory operations */ | 80 | const void *dir_ops; /* Opaque; default directory operations */ |
79 | int dir_per_block; /* dir entries per block */ | 81 | int dir_per_block; /* dir entries per block */ |
80 | int dir_per_block_bits; /* log2(dir_per_block) */ | 82 | int dir_per_block_bits; /* log2(dir_per_block) */ |
81 | 83 | ||
82 | int fatent_shift; | 84 | int fatent_shift; |
83 | struct fatent_operations *fatent_ops; | 85 | struct fatent_operations *fatent_ops; |
@@ -88,6 +90,9 @@ struct msdos_sb_info { | |||
88 | 90 | ||
89 | spinlock_t inode_hash_lock; | 91 | spinlock_t inode_hash_lock; |
90 | struct hlist_head inode_hashtable[FAT_HASH_SIZE]; | 92 | struct hlist_head inode_hashtable[FAT_HASH_SIZE]; |
93 | |||
94 | spinlock_t dir_hash_lock; | ||
95 | struct hlist_head dir_hashtable[FAT_HASH_SIZE]; | ||
91 | }; | 96 | }; |
92 | 97 | ||
93 | #define FAT_CACHE_VALID 0 /* special case for valid cache */ | 98 | #define FAT_CACHE_VALID 0 /* special case for valid cache */ |
@@ -110,6 +115,7 @@ struct msdos_inode_info { | |||
110 | int i_attrs; /* unused attribute bits */ | 115 | int i_attrs; /* unused attribute bits */ |
111 | loff_t i_pos; /* on-disk position of directory entry or 0 */ | 116 | loff_t i_pos; /* on-disk position of directory entry or 0 */ |
112 | struct hlist_node i_fat_hash; /* hash by i_location */ | 117 | struct hlist_node i_fat_hash; /* hash by i_location */ |
118 | struct hlist_node i_dir_hash; /* hash by i_logstart */ | ||
113 | struct rw_semaphore truncate_lock; /* protect bmap against truncate */ | 119 | struct rw_semaphore truncate_lock; /* protect bmap against truncate */ |
114 | struct inode vfs_inode; | 120 | struct inode vfs_inode; |
115 | }; | 121 | }; |
@@ -262,7 +268,7 @@ extern int fat_subdirs(struct inode *dir); | |||
262 | extern int fat_scan(struct inode *dir, const unsigned char *name, | 268 | extern int fat_scan(struct inode *dir, const unsigned char *name, |
263 | struct fat_slot_info *sinfo); | 269 | struct fat_slot_info *sinfo); |
264 | extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh, | 270 | extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh, |
265 | struct msdos_dir_entry **de, loff_t *i_pos); | 271 | struct msdos_dir_entry **de); |
266 | extern int fat_alloc_new_dir(struct inode *dir, struct timespec *ts); | 272 | extern int fat_alloc_new_dir(struct inode *dir, struct timespec *ts); |
267 | extern int fat_add_entries(struct inode *dir, void *slots, int nr_slots, | 273 | extern int fat_add_entries(struct inode *dir, void *slots, int nr_slots, |
268 | struct fat_slot_info *sinfo); | 274 | struct fat_slot_info *sinfo); |
@@ -322,7 +328,7 @@ extern long fat_generic_ioctl(struct file *filp, unsigned int cmd, | |||
322 | unsigned long arg); | 328 | unsigned long arg); |
323 | extern const struct file_operations fat_file_operations; | 329 | extern const struct file_operations fat_file_operations; |
324 | extern const struct inode_operations fat_file_inode_operations; | 330 | extern const struct inode_operations fat_file_inode_operations; |
325 | extern int fat_setattr(struct dentry * dentry, struct iattr * attr); | 331 | extern int fat_setattr(struct dentry *dentry, struct iattr *attr); |
326 | extern void fat_truncate_blocks(struct inode *inode, loff_t offset); | 332 | extern void fat_truncate_blocks(struct inode *inode, loff_t offset); |
327 | extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, | 333 | extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, |
328 | struct kstat *stat); | 334 | struct kstat *stat); |
@@ -340,7 +346,12 @@ extern int fat_fill_super(struct super_block *sb, void *data, int silent, | |||
340 | int isvfat, void (*setup)(struct super_block *)); | 346 | int isvfat, void (*setup)(struct super_block *)); |
341 | 347 | ||
342 | extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, | 348 | extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, |
343 | struct inode *i2); | 349 | struct inode *i2); |
350 | static inline unsigned long fat_dir_hash(int logstart) | ||
351 | { | ||
352 | return hash_32(logstart, FAT_HASH_BITS); | ||
353 | } | ||
354 | |||
344 | /* fat/misc.c */ | 355 | /* fat/misc.c */ |
345 | extern __printf(3, 4) __cold | 356 | extern __printf(3, 4) __cold |
346 | void __fat_fs_error(struct super_block *sb, int report, const char *fmt, ...); | 357 | void __fat_fs_error(struct super_block *sb, int report, const char *fmt, ...); |
@@ -366,6 +377,14 @@ extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs); | |||
366 | int fat_cache_init(void); | 377 | int fat_cache_init(void); |
367 | void fat_cache_destroy(void); | 378 | void fat_cache_destroy(void); |
368 | 379 | ||
380 | /* fat/nfs.c */ | ||
381 | struct fid; | ||
382 | extern struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid, | ||
383 | int fh_len, int fh_type); | ||
384 | extern struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid, | ||
385 | int fh_len, int fh_type); | ||
386 | extern struct dentry *fat_get_parent(struct dentry *child_dir); | ||
387 | |||
369 | /* helper for printk */ | 388 | /* helper for printk */ |
370 | typedef unsigned long long llu; | 389 | typedef unsigned long long llu; |
371 | 390 | ||
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index 31f08ab62c56..260705c58062 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c | |||
@@ -186,9 +186,6 @@ static void fat16_ent_put(struct fat_entry *fatent, int new) | |||
186 | 186 | ||
187 | static void fat32_ent_put(struct fat_entry *fatent, int new) | 187 | static void fat32_ent_put(struct fat_entry *fatent, int new) |
188 | { | 188 | { |
189 | if (new == FAT_ENT_EOF) | ||
190 | new = EOF_FAT32; | ||
191 | |||
192 | WARN_ON(new & 0xf0000000); | 189 | WARN_ON(new & 0xf0000000); |
193 | new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff; | 190 | new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff; |
194 | *fatent->u.ent32_p = cpu_to_le32(new); | 191 | *fatent->u.ent32_p = cpu_to_le32(new); |
@@ -203,15 +200,18 @@ static int fat12_ent_next(struct fat_entry *fatent) | |||
203 | 200 | ||
204 | fatent->entry++; | 201 | fatent->entry++; |
205 | if (fatent->nr_bhs == 1) { | 202 | if (fatent->nr_bhs == 1) { |
206 | WARN_ON(ent12_p[0] > (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 2))); | 203 | WARN_ON(ent12_p[0] > (u8 *)(bhs[0]->b_data + |
207 | WARN_ON(ent12_p[1] > (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))); | 204 | (bhs[0]->b_size - 2))); |
205 | WARN_ON(ent12_p[1] > (u8 *)(bhs[0]->b_data + | ||
206 | (bhs[0]->b_size - 1))); | ||
208 | if (nextp < (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))) { | 207 | if (nextp < (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))) { |
209 | ent12_p[0] = nextp - 1; | 208 | ent12_p[0] = nextp - 1; |
210 | ent12_p[1] = nextp; | 209 | ent12_p[1] = nextp; |
211 | return 1; | 210 | return 1; |
212 | } | 211 | } |
213 | } else { | 212 | } else { |
214 | WARN_ON(ent12_p[0] != (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))); | 213 | WARN_ON(ent12_p[0] != (u8 *)(bhs[0]->b_data + |
214 | (bhs[0]->b_size - 1))); | ||
215 | WARN_ON(ent12_p[1] != (u8 *)bhs[1]->b_data); | 215 | WARN_ON(ent12_p[1] != (u8 *)bhs[1]->b_data); |
216 | ent12_p[0] = nextp - 1; | 216 | ent12_p[0] = nextp - 1; |
217 | ent12_p[1] = nextp; | 217 | ent12_p[1] = nextp; |
@@ -631,7 +631,6 @@ error: | |||
631 | 631 | ||
632 | return err; | 632 | return err; |
633 | } | 633 | } |
634 | |||
635 | EXPORT_SYMBOL_GPL(fat_free_clusters); | 634 | EXPORT_SYMBOL_GPL(fat_free_clusters); |
636 | 635 | ||
637 | /* 128kb is the whole sectors for FAT12 and FAT16 */ | 636 | /* 128kb is the whole sectors for FAT12 and FAT16 */ |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 4e5a6ac54ebd..76f60c642c06 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -281,15 +281,42 @@ static inline unsigned long fat_hash(loff_t i_pos) | |||
281 | return hash_32(i_pos, FAT_HASH_BITS); | 281 | return hash_32(i_pos, FAT_HASH_BITS); |
282 | } | 282 | } |
283 | 283 | ||
284 | static void dir_hash_init(struct super_block *sb) | ||
285 | { | ||
286 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
287 | int i; | ||
288 | |||
289 | spin_lock_init(&sbi->dir_hash_lock); | ||
290 | for (i = 0; i < FAT_HASH_SIZE; i++) | ||
291 | INIT_HLIST_HEAD(&sbi->dir_hashtable[i]); | ||
292 | } | ||
293 | |||
284 | void fat_attach(struct inode *inode, loff_t i_pos) | 294 | void fat_attach(struct inode *inode, loff_t i_pos) |
285 | { | 295 | { |
286 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | 296 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); |
287 | struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos); | ||
288 | 297 | ||
289 | spin_lock(&sbi->inode_hash_lock); | 298 | if (inode->i_ino != MSDOS_ROOT_INO) { |
290 | MSDOS_I(inode)->i_pos = i_pos; | 299 | struct hlist_head *head = sbi->inode_hashtable |
291 | hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head); | 300 | + fat_hash(i_pos); |
292 | spin_unlock(&sbi->inode_hash_lock); | 301 | |
302 | spin_lock(&sbi->inode_hash_lock); | ||
303 | MSDOS_I(inode)->i_pos = i_pos; | ||
304 | hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head); | ||
305 | spin_unlock(&sbi->inode_hash_lock); | ||
306 | } | ||
307 | |||
308 | /* If NFS support is enabled, cache the mapping of start cluster | ||
309 | * to directory inode. This is used during reconnection of | ||
310 | * dentries to the filesystem root. | ||
311 | */ | ||
312 | if (S_ISDIR(inode->i_mode) && sbi->options.nfs) { | ||
313 | struct hlist_head *d_head = sbi->dir_hashtable; | ||
314 | d_head += fat_dir_hash(MSDOS_I(inode)->i_logstart); | ||
315 | |||
316 | spin_lock(&sbi->dir_hash_lock); | ||
317 | hlist_add_head(&MSDOS_I(inode)->i_dir_hash, d_head); | ||
318 | spin_unlock(&sbi->dir_hash_lock); | ||
319 | } | ||
293 | } | 320 | } |
294 | EXPORT_SYMBOL_GPL(fat_attach); | 321 | EXPORT_SYMBOL_GPL(fat_attach); |
295 | 322 | ||
@@ -300,6 +327,12 @@ void fat_detach(struct inode *inode) | |||
300 | MSDOS_I(inode)->i_pos = 0; | 327 | MSDOS_I(inode)->i_pos = 0; |
301 | hlist_del_init(&MSDOS_I(inode)->i_fat_hash); | 328 | hlist_del_init(&MSDOS_I(inode)->i_fat_hash); |
302 | spin_unlock(&sbi->inode_hash_lock); | 329 | spin_unlock(&sbi->inode_hash_lock); |
330 | |||
331 | if (S_ISDIR(inode->i_mode) && sbi->options.nfs) { | ||
332 | spin_lock(&sbi->dir_hash_lock); | ||
333 | hlist_del_init(&MSDOS_I(inode)->i_dir_hash); | ||
334 | spin_unlock(&sbi->dir_hash_lock); | ||
335 | } | ||
303 | } | 336 | } |
304 | EXPORT_SYMBOL_GPL(fat_detach); | 337 | EXPORT_SYMBOL_GPL(fat_detach); |
305 | 338 | ||
@@ -504,6 +537,7 @@ static void init_once(void *foo) | |||
504 | ei->cache_valid_id = FAT_CACHE_VALID + 1; | 537 | ei->cache_valid_id = FAT_CACHE_VALID + 1; |
505 | INIT_LIST_HEAD(&ei->cache_lru); | 538 | INIT_LIST_HEAD(&ei->cache_lru); |
506 | INIT_HLIST_NODE(&ei->i_fat_hash); | 539 | INIT_HLIST_NODE(&ei->i_fat_hash); |
540 | INIT_HLIST_NODE(&ei->i_dir_hash); | ||
507 | inode_init_once(&ei->vfs_inode); | 541 | inode_init_once(&ei->vfs_inode); |
508 | } | 542 | } |
509 | 543 | ||
@@ -668,125 +702,9 @@ static const struct super_operations fat_sops = { | |||
668 | .show_options = fat_show_options, | 702 | .show_options = fat_show_options, |
669 | }; | 703 | }; |
670 | 704 | ||
671 | /* | ||
672 | * a FAT file handle with fhtype 3 is | ||
673 | * 0/ i_ino - for fast, reliable lookup if still in the cache | ||
674 | * 1/ i_generation - to see if i_ino is still valid | ||
675 | * bit 0 == 0 iff directory | ||
676 | * 2/ i_pos(8-39) - if ino has changed, but still in cache | ||
677 | * 3/ i_pos(4-7)|i_logstart - to semi-verify inode found at i_pos | ||
678 | * 4/ i_pos(0-3)|parent->i_logstart - maybe used to hunt for the file on disc | ||
679 | * | ||
680 | * Hack for NFSv2: Maximum FAT entry number is 28bits and maximum | ||
681 | * i_pos is 40bits (blocknr(32) + dir offset(8)), so two 4bits | ||
682 | * of i_logstart is used to store the directory entry offset. | ||
683 | */ | ||
684 | |||
685 | static struct dentry *fat_fh_to_dentry(struct super_block *sb, | ||
686 | struct fid *fid, int fh_len, int fh_type) | ||
687 | { | ||
688 | struct inode *inode = NULL; | ||
689 | u32 *fh = fid->raw; | ||
690 | |||
691 | if (fh_len < 5 || fh_type != 3) | ||
692 | return NULL; | ||
693 | |||
694 | inode = ilookup(sb, fh[0]); | ||
695 | if (!inode || inode->i_generation != fh[1]) { | ||
696 | if (inode) | ||
697 | iput(inode); | ||
698 | inode = NULL; | ||
699 | } | ||
700 | if (!inode) { | ||
701 | loff_t i_pos; | ||
702 | int i_logstart = fh[3] & 0x0fffffff; | ||
703 | |||
704 | i_pos = (loff_t)fh[2] << 8; | ||
705 | i_pos |= ((fh[3] >> 24) & 0xf0) | (fh[4] >> 28); | ||
706 | |||
707 | /* try 2 - see if i_pos is in F-d-c | ||
708 | * require i_logstart to be the same | ||
709 | * Will fail if you truncate and then re-write | ||
710 | */ | ||
711 | |||
712 | inode = fat_iget(sb, i_pos); | ||
713 | if (inode && MSDOS_I(inode)->i_logstart != i_logstart) { | ||
714 | iput(inode); | ||
715 | inode = NULL; | ||
716 | } | ||
717 | } | ||
718 | |||
719 | /* | ||
720 | * For now, do nothing if the inode is not found. | ||
721 | * | ||
722 | * What we could do is: | ||
723 | * | ||
724 | * - follow the file starting at fh[4], and record the ".." entry, | ||
725 | * and the name of the fh[2] entry. | ||
726 | * - then follow the ".." file finding the next step up. | ||
727 | * | ||
728 | * This way we build a path to the root of the tree. If this works, we | ||
729 | * lookup the path and so get this inode into the cache. Finally try | ||
730 | * the fat_iget lookup again. If that fails, then we are totally out | ||
731 | * of luck. But all that is for another day | ||
732 | */ | ||
733 | return d_obtain_alias(inode); | ||
734 | } | ||
735 | |||
736 | static int | ||
737 | fat_encode_fh(struct inode *inode, __u32 *fh, int *lenp, struct inode *parent) | ||
738 | { | ||
739 | int len = *lenp; | ||
740 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||
741 | loff_t i_pos; | ||
742 | |||
743 | if (len < 5) { | ||
744 | *lenp = 5; | ||
745 | return 255; /* no room */ | ||
746 | } | ||
747 | |||
748 | i_pos = fat_i_pos_read(sbi, inode); | ||
749 | *lenp = 5; | ||
750 | fh[0] = inode->i_ino; | ||
751 | fh[1] = inode->i_generation; | ||
752 | fh[2] = i_pos >> 8; | ||
753 | fh[3] = ((i_pos & 0xf0) << 24) | MSDOS_I(inode)->i_logstart; | ||
754 | fh[4] = (i_pos & 0x0f) << 28; | ||
755 | if (parent) | ||
756 | fh[4] |= MSDOS_I(parent)->i_logstart; | ||
757 | return 3; | ||
758 | } | ||
759 | |||
760 | static struct dentry *fat_get_parent(struct dentry *child) | ||
761 | { | ||
762 | struct super_block *sb = child->d_sb; | ||
763 | struct buffer_head *bh; | ||
764 | struct msdos_dir_entry *de; | ||
765 | loff_t i_pos; | ||
766 | struct dentry *parent; | ||
767 | struct inode *inode; | ||
768 | int err; | ||
769 | |||
770 | lock_super(sb); | ||
771 | |||
772 | err = fat_get_dotdot_entry(child->d_inode, &bh, &de, &i_pos); | ||
773 | if (err) { | ||
774 | parent = ERR_PTR(err); | ||
775 | goto out; | ||
776 | } | ||
777 | inode = fat_build_inode(sb, de, i_pos); | ||
778 | brelse(bh); | ||
779 | |||
780 | parent = d_obtain_alias(inode); | ||
781 | out: | ||
782 | unlock_super(sb); | ||
783 | |||
784 | return parent; | ||
785 | } | ||
786 | |||
787 | static const struct export_operations fat_export_ops = { | 705 | static const struct export_operations fat_export_ops = { |
788 | .encode_fh = fat_encode_fh, | ||
789 | .fh_to_dentry = fat_fh_to_dentry, | 706 | .fh_to_dentry = fat_fh_to_dentry, |
707 | .fh_to_parent = fat_fh_to_parent, | ||
790 | .get_parent = fat_get_parent, | 708 | .get_parent = fat_get_parent, |
791 | }; | 709 | }; |
792 | 710 | ||
@@ -836,6 +754,8 @@ static int fat_show_options(struct seq_file *m, struct dentry *root) | |||
836 | seq_puts(m, ",usefree"); | 754 | seq_puts(m, ",usefree"); |
837 | if (opts->quiet) | 755 | if (opts->quiet) |
838 | seq_puts(m, ",quiet"); | 756 | seq_puts(m, ",quiet"); |
757 | if (opts->nfs) | ||
758 | seq_puts(m, ",nfs"); | ||
839 | if (opts->showexec) | 759 | if (opts->showexec) |
840 | seq_puts(m, ",showexec"); | 760 | seq_puts(m, ",showexec"); |
841 | if (opts->sys_immutable) | 761 | if (opts->sys_immutable) |
@@ -880,7 +800,7 @@ enum { | |||
880 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, | 800 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, |
881 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, | 801 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, |
882 | Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, | 802 | Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, |
883 | Opt_err_panic, Opt_err_ro, Opt_discard, Opt_err, | 803 | Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_err, |
884 | }; | 804 | }; |
885 | 805 | ||
886 | static const match_table_t fat_tokens = { | 806 | static const match_table_t fat_tokens = { |
@@ -909,6 +829,7 @@ static const match_table_t fat_tokens = { | |||
909 | {Opt_err_panic, "errors=panic"}, | 829 | {Opt_err_panic, "errors=panic"}, |
910 | {Opt_err_ro, "errors=remount-ro"}, | 830 | {Opt_err_ro, "errors=remount-ro"}, |
911 | {Opt_discard, "discard"}, | 831 | {Opt_discard, "discard"}, |
832 | {Opt_nfs, "nfs"}, | ||
912 | {Opt_obsolete, "conv=binary"}, | 833 | {Opt_obsolete, "conv=binary"}, |
913 | {Opt_obsolete, "conv=text"}, | 834 | {Opt_obsolete, "conv=text"}, |
914 | {Opt_obsolete, "conv=auto"}, | 835 | {Opt_obsolete, "conv=auto"}, |
@@ -989,6 +910,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, | |||
989 | opts->numtail = 1; | 910 | opts->numtail = 1; |
990 | opts->usefree = opts->nocase = 0; | 911 | opts->usefree = opts->nocase = 0; |
991 | opts->tz_utc = 0; | 912 | opts->tz_utc = 0; |
913 | opts->nfs = 0; | ||
992 | opts->errors = FAT_ERRORS_RO; | 914 | opts->errors = FAT_ERRORS_RO; |
993 | *debug = 0; | 915 | *debug = 0; |
994 | 916 | ||
@@ -1153,6 +1075,9 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, | |||
1153 | case Opt_discard: | 1075 | case Opt_discard: |
1154 | opts->discard = 1; | 1076 | opts->discard = 1; |
1155 | break; | 1077 | break; |
1078 | case Opt_nfs: | ||
1079 | opts->nfs = 1; | ||
1080 | break; | ||
1156 | 1081 | ||
1157 | /* obsolete mount options */ | 1082 | /* obsolete mount options */ |
1158 | case Opt_obsolete: | 1083 | case Opt_obsolete: |
@@ -1443,6 +1368,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1443 | 1368 | ||
1444 | /* set up enough so that it can read an inode */ | 1369 | /* set up enough so that it can read an inode */ |
1445 | fat_hash_init(sb); | 1370 | fat_hash_init(sb); |
1371 | dir_hash_init(sb); | ||
1446 | fat_ent_access_init(sb); | 1372 | fat_ent_access_init(sb); |
1447 | 1373 | ||
1448 | /* | 1374 | /* |
@@ -1497,6 +1423,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, | |||
1497 | } | 1423 | } |
1498 | error = -ENOMEM; | 1424 | error = -ENOMEM; |
1499 | insert_inode_hash(root_inode); | 1425 | insert_inode_hash(root_inode); |
1426 | fat_attach(root_inode, 0); | ||
1500 | sb->s_root = d_make_root(root_inode); | 1427 | sb->s_root = d_make_root(root_inode); |
1501 | if (!sb->s_root) { | 1428 | if (!sb->s_root) { |
1502 | fat_msg(sb, KERN_ERR, "get root inode failed"); | 1429 | fat_msg(sb, KERN_ERR, "get root inode failed"); |
@@ -1536,18 +1463,14 @@ static int writeback_inode(struct inode *inode) | |||
1536 | { | 1463 | { |
1537 | 1464 | ||
1538 | int ret; | 1465 | int ret; |
1539 | struct address_space *mapping = inode->i_mapping; | 1466 | |
1540 | struct writeback_control wbc = { | 1467 | /* if we used wait=1, sync_inode_metadata waits for the io for the |
1541 | .sync_mode = WB_SYNC_NONE, | 1468 | * inode to finish. So wait=0 is sent down to sync_inode_metadata |
1542 | .nr_to_write = 0, | ||
1543 | }; | ||
1544 | /* if we used WB_SYNC_ALL, sync_inode waits for the io for the | ||
1545 | * inode to finish. So WB_SYNC_NONE is sent down to sync_inode | ||
1546 | * and filemap_fdatawrite is used for the data blocks | 1469 | * and filemap_fdatawrite is used for the data blocks |
1547 | */ | 1470 | */ |
1548 | ret = sync_inode(inode, &wbc); | 1471 | ret = sync_inode_metadata(inode, 0); |
1549 | if (!ret) | 1472 | if (!ret) |
1550 | ret = filemap_fdatawrite(mapping); | 1473 | ret = filemap_fdatawrite(inode->i_mapping); |
1551 | return ret; | 1474 | return ret; |
1552 | } | 1475 | } |
1553 | 1476 | ||
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index b0e12bf9f4a1..c1055e778fff 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c | |||
@@ -407,7 +407,7 @@ out: | |||
407 | static int msdos_unlink(struct inode *dir, struct dentry *dentry) | 407 | static int msdos_unlink(struct inode *dir, struct dentry *dentry) |
408 | { | 408 | { |
409 | struct inode *inode = dentry->d_inode; | 409 | struct inode *inode = dentry->d_inode; |
410 | struct super_block *sb= inode->i_sb; | 410 | struct super_block *sb = inode->i_sb; |
411 | struct fat_slot_info sinfo; | 411 | struct fat_slot_info sinfo; |
412 | int err; | 412 | int err; |
413 | 413 | ||
@@ -440,7 +440,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, | |||
440 | struct inode *old_inode, *new_inode; | 440 | struct inode *old_inode, *new_inode; |
441 | struct fat_slot_info old_sinfo, sinfo; | 441 | struct fat_slot_info old_sinfo, sinfo; |
442 | struct timespec ts; | 442 | struct timespec ts; |
443 | loff_t dotdot_i_pos, new_i_pos; | 443 | loff_t new_i_pos; |
444 | int err, old_attrs, is_dir, update_dotdot, corrupt = 0; | 444 | int err, old_attrs, is_dir, update_dotdot, corrupt = 0; |
445 | 445 | ||
446 | old_sinfo.bh = sinfo.bh = dotdot_bh = NULL; | 446 | old_sinfo.bh = sinfo.bh = dotdot_bh = NULL; |
@@ -456,8 +456,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, | |||
456 | is_dir = S_ISDIR(old_inode->i_mode); | 456 | is_dir = S_ISDIR(old_inode->i_mode); |
457 | update_dotdot = (is_dir && old_dir != new_dir); | 457 | update_dotdot = (is_dir && old_dir != new_dir); |
458 | if (update_dotdot) { | 458 | if (update_dotdot) { |
459 | if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de, | 459 | if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de)) { |
460 | &dotdot_i_pos) < 0) { | ||
461 | err = -EIO; | 460 | err = -EIO; |
462 | goto out; | 461 | goto out; |
463 | } | 462 | } |
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 6a6d8c0715a1..e535dd75b986 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c | |||
@@ -914,7 +914,7 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
914 | struct inode *old_inode, *new_inode; | 914 | struct inode *old_inode, *new_inode; |
915 | struct fat_slot_info old_sinfo, sinfo; | 915 | struct fat_slot_info old_sinfo, sinfo; |
916 | struct timespec ts; | 916 | struct timespec ts; |
917 | loff_t dotdot_i_pos, new_i_pos; | 917 | loff_t new_i_pos; |
918 | int err, is_dir, update_dotdot, corrupt = 0; | 918 | int err, is_dir, update_dotdot, corrupt = 0; |
919 | struct super_block *sb = old_dir->i_sb; | 919 | struct super_block *sb = old_dir->i_sb; |
920 | 920 | ||
@@ -929,8 +929,7 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
929 | is_dir = S_ISDIR(old_inode->i_mode); | 929 | is_dir = S_ISDIR(old_inode->i_mode); |
930 | update_dotdot = (is_dir && old_dir != new_dir); | 930 | update_dotdot = (is_dir && old_dir != new_dir); |
931 | if (update_dotdot) { | 931 | if (update_dotdot) { |
932 | if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de, | 932 | if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de)) { |
933 | &dotdot_i_pos) < 0) { | ||
934 | err = -EIO; | 933 | err = -EIO; |
935 | goto out; | 934 | goto out; |
936 | } | 935 | } |
diff --git a/fs/fat/nfs.c b/fs/fat/nfs.c new file mode 100644 index 000000000000..ef4b5faba87b --- /dev/null +++ b/fs/fat/nfs.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* fs/fat/nfs.c | ||
2 | * | ||
3 | * This software is licensed under the terms of the GNU General Public | ||
4 | * License version 2, as published by the Free Software Foundation, and | ||
5 | * may be copied, distributed, and modified under those terms. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/exportfs.h> | ||
15 | #include "fat.h" | ||
16 | |||
17 | /** | ||
18 | * Look up a directory inode given its starting cluster. | ||
19 | */ | ||
20 | static struct inode *fat_dget(struct super_block *sb, int i_logstart) | ||
21 | { | ||
22 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
23 | struct hlist_head *head; | ||
24 | struct hlist_node *_p; | ||
25 | struct msdos_inode_info *i; | ||
26 | struct inode *inode = NULL; | ||
27 | |||
28 | head = sbi->dir_hashtable + fat_dir_hash(i_logstart); | ||
29 | spin_lock(&sbi->dir_hash_lock); | ||
30 | hlist_for_each_entry(i, _p, head, i_dir_hash) { | ||
31 | BUG_ON(i->vfs_inode.i_sb != sb); | ||
32 | if (i->i_logstart != i_logstart) | ||
33 | continue; | ||
34 | inode = igrab(&i->vfs_inode); | ||
35 | if (inode) | ||
36 | break; | ||
37 | } | ||
38 | spin_unlock(&sbi->dir_hash_lock); | ||
39 | return inode; | ||
40 | } | ||
41 | |||
42 | static struct inode *fat_nfs_get_inode(struct super_block *sb, | ||
43 | u64 ino, u32 generation) | ||
44 | { | ||
45 | struct inode *inode; | ||
46 | |||
47 | if ((ino < MSDOS_ROOT_INO) || (ino == MSDOS_FSINFO_INO)) | ||
48 | return NULL; | ||
49 | |||
50 | inode = ilookup(sb, ino); | ||
51 | if (inode && generation && (inode->i_generation != generation)) { | ||
52 | iput(inode); | ||
53 | inode = NULL; | ||
54 | } | ||
55 | |||
56 | return inode; | ||
57 | } | ||
58 | |||
59 | /** | ||
60 | * Map a NFS file handle to a corresponding dentry. | ||
61 | * The dentry may or may not be connected to the filesystem root. | ||
62 | */ | ||
63 | struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid, | ||
64 | int fh_len, int fh_type) | ||
65 | { | ||
66 | return generic_fh_to_dentry(sb, fid, fh_len, fh_type, | ||
67 | fat_nfs_get_inode); | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * Find the parent for a file specified by NFS handle. | ||
72 | * This requires that the handle contain the i_ino of the parent. | ||
73 | */ | ||
74 | struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid, | ||
75 | int fh_len, int fh_type) | ||
76 | { | ||
77 | return generic_fh_to_parent(sb, fid, fh_len, fh_type, | ||
78 | fat_nfs_get_inode); | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * Find the parent for a directory that is not currently connected to | ||
83 | * the filesystem root. | ||
84 | * | ||
85 | * On entry, the caller holds child_dir->d_inode->i_mutex. | ||
86 | */ | ||
87 | struct dentry *fat_get_parent(struct dentry *child_dir) | ||
88 | { | ||
89 | struct super_block *sb = child_dir->d_sb; | ||
90 | struct buffer_head *bh = NULL; | ||
91 | struct msdos_dir_entry *de; | ||
92 | struct inode *parent_inode = NULL; | ||
93 | |||
94 | if (!fat_get_dotdot_entry(child_dir->d_inode, &bh, &de)) { | ||
95 | int parent_logstart = fat_get_start(MSDOS_SB(sb), de); | ||
96 | parent_inode = fat_dget(sb, parent_logstart); | ||
97 | } | ||
98 | brelse(bh); | ||
99 | |||
100 | return d_obtain_alias(parent_inode); | ||
101 | } | ||
diff --git a/fs/hpfs/anode.c b/fs/hpfs/anode.c index 4bae4a4a60b1..2d5b254ad9e2 100644 --- a/fs/hpfs/anode.c +++ b/fs/hpfs/anode.c | |||
@@ -102,7 +102,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi | |||
102 | return -1; | 102 | return -1; |
103 | } | 103 | } |
104 | if (hpfs_alloc_if_possible(s, se = le32_to_cpu(btree->u.external[n].disk_secno) + le32_to_cpu(btree->u.external[n].length))) { | 104 | if (hpfs_alloc_if_possible(s, se = le32_to_cpu(btree->u.external[n].disk_secno) + le32_to_cpu(btree->u.external[n].length))) { |
105 | btree->u.external[n].length = cpu_to_le32(le32_to_cpu(btree->u.external[n].length) + 1); | 105 | le32_add_cpu(&btree->u.external[n].length, 1); |
106 | mark_buffer_dirty(bh); | 106 | mark_buffer_dirty(bh); |
107 | brelse(bh); | 107 | brelse(bh); |
108 | return se; | 108 | return se; |
@@ -153,7 +153,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi | |||
153 | btree = &anode->btree; | 153 | btree = &anode->btree; |
154 | } | 154 | } |
155 | btree->n_free_nodes--; n = btree->n_used_nodes++; | 155 | btree->n_free_nodes--; n = btree->n_used_nodes++; |
156 | btree->first_free = cpu_to_le16(le16_to_cpu(btree->first_free) + 12); | 156 | le16_add_cpu(&btree->first_free, 12); |
157 | btree->u.external[n].disk_secno = cpu_to_le32(se); | 157 | btree->u.external[n].disk_secno = cpu_to_le32(se); |
158 | btree->u.external[n].file_secno = cpu_to_le32(fs); | 158 | btree->u.external[n].file_secno = cpu_to_le32(fs); |
159 | btree->u.external[n].length = cpu_to_le32(1); | 159 | btree->u.external[n].length = cpu_to_le32(1); |
@@ -174,7 +174,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi | |||
174 | } | 174 | } |
175 | if (btree->n_free_nodes) { | 175 | if (btree->n_free_nodes) { |
176 | btree->n_free_nodes--; n = btree->n_used_nodes++; | 176 | btree->n_free_nodes--; n = btree->n_used_nodes++; |
177 | btree->first_free = cpu_to_le16(le16_to_cpu(btree->first_free) + 8); | 177 | le16_add_cpu(&btree->first_free, 8); |
178 | btree->u.internal[n].file_secno = cpu_to_le32(-1); | 178 | btree->u.internal[n].file_secno = cpu_to_le32(-1); |
179 | btree->u.internal[n].down = cpu_to_le32(na); | 179 | btree->u.internal[n].down = cpu_to_le32(na); |
180 | btree->u.internal[n-1].file_secno = cpu_to_le32(fs); | 180 | btree->u.internal[n-1].file_secno = cpu_to_le32(fs); |
diff --git a/fs/hpfs/dnode.c b/fs/hpfs/dnode.c index 3228c524ebe5..4364b2a02c5d 100644 --- a/fs/hpfs/dnode.c +++ b/fs/hpfs/dnode.c | |||
@@ -145,10 +145,10 @@ static void set_last_pointer(struct super_block *s, struct dnode *d, dnode_secno | |||
145 | } | 145 | } |
146 | } | 146 | } |
147 | if (ptr) { | 147 | if (ptr) { |
148 | d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) + 4); | 148 | le32_add_cpu(&d->first_free, 4); |
149 | if (le32_to_cpu(d->first_free) > 2048) { | 149 | if (le32_to_cpu(d->first_free) > 2048) { |
150 | hpfs_error(s, "set_last_pointer: too long dnode %08x", le32_to_cpu(d->self)); | 150 | hpfs_error(s, "set_last_pointer: too long dnode %08x", le32_to_cpu(d->self)); |
151 | d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) - 4); | 151 | le32_add_cpu(&d->first_free, -4); |
152 | return; | 152 | return; |
153 | } | 153 | } |
154 | de->length = cpu_to_le16(36); | 154 | de->length = cpu_to_le16(36); |
@@ -184,7 +184,7 @@ struct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d, | |||
184 | de->not_8x3 = hpfs_is_name_long(name, namelen); | 184 | de->not_8x3 = hpfs_is_name_long(name, namelen); |
185 | de->namelen = namelen; | 185 | de->namelen = namelen; |
186 | memcpy(de->name, name, namelen); | 186 | memcpy(de->name, name, namelen); |
187 | d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) + d_size); | 187 | le32_add_cpu(&d->first_free, d_size); |
188 | return de; | 188 | return de; |
189 | } | 189 | } |
190 | 190 | ||
@@ -314,7 +314,7 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, | |||
314 | set_last_pointer(i->i_sb, ad, de->down ? de_down_pointer(de) : 0); | 314 | set_last_pointer(i->i_sb, ad, de->down ? de_down_pointer(de) : 0); |
315 | de = de_next_de(de); | 315 | de = de_next_de(de); |
316 | memmove((char *)nd + 20, de, le32_to_cpu(nd->first_free) + (char *)nd - (char *)de); | 316 | memmove((char *)nd + 20, de, le32_to_cpu(nd->first_free) + (char *)nd - (char *)de); |
317 | nd->first_free = cpu_to_le32(le32_to_cpu(nd->first_free) - ((char *)de - (char *)nd - 20)); | 317 | le32_add_cpu(&nd->first_free, -((char *)de - (char *)nd - 20)); |
318 | memcpy(d, nd, le32_to_cpu(nd->first_free)); | 318 | memcpy(d, nd, le32_to_cpu(nd->first_free)); |
319 | for_all_poss(i, hpfs_pos_del, (loff_t)dno << 4, pos); | 319 | for_all_poss(i, hpfs_pos_del, (loff_t)dno << 4, pos); |
320 | fix_up_ptrs(i->i_sb, ad); | 320 | fix_up_ptrs(i->i_sb, ad); |
@@ -474,8 +474,8 @@ static secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to) | |||
474 | hpfs_brelse4(&qbh); | 474 | hpfs_brelse4(&qbh); |
475 | return 0; | 475 | return 0; |
476 | } | 476 | } |
477 | dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) - 4); | 477 | le32_add_cpu(&dnode->first_free, -4); |
478 | de->length = cpu_to_le16(le16_to_cpu(de->length) - 4); | 478 | le16_add_cpu(&de->length, -4); |
479 | de->down = 0; | 479 | de->down = 0; |
480 | hpfs_mark_4buffers_dirty(&qbh); | 480 | hpfs_mark_4buffers_dirty(&qbh); |
481 | dno = up; | 481 | dno = up; |
@@ -570,8 +570,8 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) | |||
570 | for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, ((loff_t)up << 4) | p); | 570 | for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, ((loff_t)up << 4) | p); |
571 | if (!down) { | 571 | if (!down) { |
572 | de->down = 0; | 572 | de->down = 0; |
573 | de->length = cpu_to_le16(le16_to_cpu(de->length) - 4); | 573 | le16_add_cpu(&de->length, -4); |
574 | dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) - 4); | 574 | le32_add_cpu(&dnode->first_free, -4); |
575 | memmove(de_next_de(de), (char *)de_next_de(de) + 4, | 575 | memmove(de_next_de(de), (char *)de_next_de(de) + 4, |
576 | (char *)dnode + le32_to_cpu(dnode->first_free) - (char *)de_next_de(de)); | 576 | (char *)dnode + le32_to_cpu(dnode->first_free) - (char *)de_next_de(de)); |
577 | } else { | 577 | } else { |
@@ -647,14 +647,14 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) | |||
647 | printk("HPFS: warning: unbalanced dnode tree, see hpfs.txt 4 more info\n"); | 647 | printk("HPFS: warning: unbalanced dnode tree, see hpfs.txt 4 more info\n"); |
648 | printk("HPFS: warning: goin'on\n"); | 648 | printk("HPFS: warning: goin'on\n"); |
649 | } | 649 | } |
650 | del->length = cpu_to_le16(le16_to_cpu(del->length) + 4); | 650 | le16_add_cpu(&del->length, 4); |
651 | del->down = 1; | 651 | del->down = 1; |
652 | d1->first_free = cpu_to_le32(le32_to_cpu(d1->first_free) + 4); | 652 | le32_add_cpu(&d1->first_free, 4); |
653 | } | 653 | } |
654 | if (dlp && !down) { | 654 | if (dlp && !down) { |
655 | del->length = cpu_to_le16(le16_to_cpu(del->length) - 4); | 655 | le16_add_cpu(&del->length, -4); |
656 | del->down = 0; | 656 | del->down = 0; |
657 | d1->first_free = cpu_to_le32(le32_to_cpu(d1->first_free) - 4); | 657 | le32_add_cpu(&d1->first_free, -4); |
658 | } else if (down) | 658 | } else if (down) |
659 | *(__le32 *) ((void *) del + le16_to_cpu(del->length) - 4) = cpu_to_le32(down); | 659 | *(__le32 *) ((void *) del + le16_to_cpu(del->length) - 4) = cpu_to_le32(down); |
660 | } else goto endm; | 660 | } else goto endm; |
@@ -668,9 +668,9 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno) | |||
668 | memcpy(de_cp, de_prev, le16_to_cpu(de_prev->length)); | 668 | memcpy(de_cp, de_prev, le16_to_cpu(de_prev->length)); |
669 | hpfs_delete_de(i->i_sb, dnode, de_prev); | 669 | hpfs_delete_de(i->i_sb, dnode, de_prev); |
670 | if (!de_prev->down) { | 670 | if (!de_prev->down) { |
671 | de_prev->length = cpu_to_le16(le16_to_cpu(de_prev->length) + 4); | 671 | le16_add_cpu(&de_prev->length, 4); |
672 | de_prev->down = 1; | 672 | de_prev->down = 1; |
673 | dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) + 4); | 673 | le32_add_cpu(&dnode->first_free, 4); |
674 | } | 674 | } |
675 | *(__le32 *) ((void *) de_prev + le16_to_cpu(de_prev->length) - 4) = cpu_to_le32(ndown); | 675 | *(__le32 *) ((void *) de_prev + le16_to_cpu(de_prev->length) - 4) = cpu_to_le32(ndown); |
676 | hpfs_mark_4buffers_dirty(&qbh); | 676 | hpfs_mark_4buffers_dirty(&qbh); |
diff --git a/fs/omfs/file.c b/fs/omfs/file.c index 2c6d95257a4d..77e3cb2962b4 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c | |||
@@ -146,8 +146,7 @@ static int omfs_grow_extent(struct inode *inode, struct omfs_extent *oe, | |||
146 | be64_to_cpu(entry->e_blocks); | 146 | be64_to_cpu(entry->e_blocks); |
147 | 147 | ||
148 | if (omfs_allocate_block(inode->i_sb, new_block)) { | 148 | if (omfs_allocate_block(inode->i_sb, new_block)) { |
149 | entry->e_blocks = | 149 | be64_add_cpu(&entry->e_blocks, 1); |
150 | cpu_to_be64(be64_to_cpu(entry->e_blocks) + 1); | ||
151 | terminator->e_blocks = ~(cpu_to_be64( | 150 | terminator->e_blocks = ~(cpu_to_be64( |
152 | be64_to_cpu(~terminator->e_blocks) + 1)); | 151 | be64_to_cpu(~terminator->e_blocks) + 1)); |
153 | goto out; | 152 | goto out; |
@@ -177,7 +176,7 @@ static int omfs_grow_extent(struct inode *inode, struct omfs_extent *oe, | |||
177 | be64_to_cpu(~terminator->e_blocks) + (u64) new_count)); | 176 | be64_to_cpu(~terminator->e_blocks) + (u64) new_count)); |
178 | 177 | ||
179 | /* write in new entry */ | 178 | /* write in new entry */ |
180 | oe->e_extent_count = cpu_to_be32(1 + be32_to_cpu(oe->e_extent_count)); | 179 | be32_add_cpu(&oe->e_extent_count, 1); |
181 | 180 | ||
182 | out: | 181 | out: |
183 | *ret_block = new_block; | 182 | *ret_block = new_block; |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index b3647fe6a608..0d80cef4cfb9 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -427,7 +427,7 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, | |||
427 | if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { | 427 | if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { |
428 | pde_get(de); | 428 | pde_get(de); |
429 | spin_unlock(&proc_subdir_lock); | 429 | spin_unlock(&proc_subdir_lock); |
430 | error = -EINVAL; | 430 | error = -ENOMEM; |
431 | inode = proc_get_inode(dir->i_sb, de); | 431 | inode = proc_get_inode(dir->i_sb, de); |
432 | goto out_unlock; | 432 | goto out_unlock; |
433 | } | 433 | } |
@@ -605,7 +605,8 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, | |||
605 | unsigned int len; | 605 | unsigned int len; |
606 | 606 | ||
607 | /* make sure name is valid */ | 607 | /* make sure name is valid */ |
608 | if (!name || !strlen(name)) goto out; | 608 | if (!name || !strlen(name)) |
609 | goto out; | ||
609 | 610 | ||
610 | if (xlate_proc_name(name, parent, &fn) != 0) | 611 | if (xlate_proc_name(name, parent, &fn) != 0) |
611 | goto out; | 612 | goto out; |
@@ -616,20 +617,18 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, | |||
616 | 617 | ||
617 | len = strlen(fn); | 618 | len = strlen(fn); |
618 | 619 | ||
619 | ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL); | 620 | ent = kzalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL); |
620 | if (!ent) goto out; | 621 | if (!ent) |
622 | goto out; | ||
621 | 623 | ||
622 | memset(ent, 0, sizeof(struct proc_dir_entry)); | ||
623 | memcpy(ent->name, fn, len + 1); | 624 | memcpy(ent->name, fn, len + 1); |
624 | ent->namelen = len; | 625 | ent->namelen = len; |
625 | ent->mode = mode; | 626 | ent->mode = mode; |
626 | ent->nlink = nlink; | 627 | ent->nlink = nlink; |
627 | atomic_set(&ent->count, 1); | 628 | atomic_set(&ent->count, 1); |
628 | ent->pde_users = 0; | ||
629 | spin_lock_init(&ent->pde_unload_lock); | 629 | spin_lock_init(&ent->pde_unload_lock); |
630 | ent->pde_unload_completion = NULL; | ||
631 | INIT_LIST_HEAD(&ent->pde_openers); | 630 | INIT_LIST_HEAD(&ent->pde_openers); |
632 | out: | 631 | out: |
633 | return ent; | 632 | return ent; |
634 | } | 633 | } |
635 | 634 | ||
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 7ac817b64a71..3b22bbdee9ec 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -450,7 +450,6 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) | |||
450 | return NULL; | 450 | return NULL; |
451 | if (inode->i_state & I_NEW) { | 451 | if (inode->i_state & I_NEW) { |
452 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 452 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
453 | PROC_I(inode)->fd = 0; | ||
454 | PROC_I(inode)->pde = de; | 453 | PROC_I(inode)->pde = de; |
455 | 454 | ||
456 | if (de->mode) { | 455 | if (de->mode) { |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 67925a7bd8cb..cceaab07ad54 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -103,7 +103,7 @@ static inline int task_dumpable(struct task_struct *task) | |||
103 | if (mm) | 103 | if (mm) |
104 | dumpable = get_dumpable(mm); | 104 | dumpable = get_dumpable(mm); |
105 | task_unlock(task); | 105 | task_unlock(task); |
106 | if(dumpable == 1) | 106 | if (dumpable == SUID_DUMPABLE_ENABLED) |
107 | return 1; | 107 | return 1; |
108 | return 0; | 108 | return 0; |
109 | } | 109 | } |
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index eb7cc91b7258..dcd56f84db7e 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -266,8 +266,7 @@ void sysctl_head_put(struct ctl_table_header *head) | |||
266 | 266 | ||
267 | static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) | 267 | static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) |
268 | { | 268 | { |
269 | if (!head) | 269 | BUG_ON(!head); |
270 | BUG(); | ||
271 | spin_lock(&sysctl_lock); | 270 | spin_lock(&sysctl_lock); |
272 | if (!use_table(head)) | 271 | if (!use_table(head)) |
273 | head = ERR_PTR(-ENOENT); | 272 | head = ERR_PTR(-ENOENT); |
diff --git a/fs/proc/root.c b/fs/proc/root.c index 9a2d9fd7cadd..9889a92d2e01 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
@@ -61,7 +61,7 @@ static int proc_parse_options(char *options, struct pid_namespace *pid) | |||
61 | if (!*p) | 61 | if (!*p) |
62 | continue; | 62 | continue; |
63 | 63 | ||
64 | args[0].to = args[0].from = 0; | 64 | args[0].to = args[0].from = NULL; |
65 | token = match_token(p, tokens, args); | 65 | token = match_token(p, tokens, args); |
66 | switch (token) { | 66 | switch (token) { |
67 | case Opt_gid: | 67 | case Opt_gid: |
diff --git a/fs/super.c b/fs/super.c index 5fdf7ff32c4e..a3bc935069d9 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -865,7 +865,7 @@ int get_anon_bdev(dev_t *p) | |||
865 | else if (error) | 865 | else if (error) |
866 | return -EAGAIN; | 866 | return -EAGAIN; |
867 | 867 | ||
868 | if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) { | 868 | if ((dev & MAX_IDR_MASK) == (1 << MINORBITS)) { |
869 | spin_lock(&unnamed_dev_lock); | 869 | spin_lock(&unnamed_dev_lock); |
870 | ida_remove(&unnamed_dev_ida, dev); | 870 | ida_remove(&unnamed_dev_ida, dev); |
871 | if (unnamed_dev_start > dev) | 871 | if (unnamed_dev_start > dev) |