diff options
Diffstat (limited to 'fs')
122 files changed, 4127 insertions, 3004 deletions
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 678c02f1ae23..a452ac67fc94 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c | |||
@@ -224,12 +224,11 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
224 | } | 224 | } |
225 | 225 | ||
226 | static void | 226 | static void |
227 | v9fs_umount_begin(struct vfsmount *vfsmnt, int flags) | 227 | v9fs_umount_begin(struct super_block *sb) |
228 | { | 228 | { |
229 | struct v9fs_session_info *v9ses = vfsmnt->mnt_sb->s_fs_info; | 229 | struct v9fs_session_info *v9ses = sb->s_fs_info; |
230 | 230 | ||
231 | if (flags & MNT_FORCE) | 231 | v9fs_session_cancel(v9ses); |
232 | v9fs_session_cancel(v9ses); | ||
233 | } | 232 | } |
234 | 233 | ||
235 | static const struct super_operations v9fs_super_ops = { | 234 | static const struct super_operations v9fs_super_ops = { |
diff --git a/fs/Kconfig b/fs/Kconfig index 028ae38ecc52..2e43d46f65d6 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -411,7 +411,7 @@ config JFS_STATISTICS | |||
411 | to be made available to the user in the /proc/fs/jfs/ directory. | 411 | to be made available to the user in the /proc/fs/jfs/ directory. |
412 | 412 | ||
413 | config FS_POSIX_ACL | 413 | config FS_POSIX_ACL |
414 | # Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs) | 414 | # Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4) |
415 | # | 415 | # |
416 | # NOTE: you can implement Posix ACLs without these helpers (XFS does). | 416 | # NOTE: you can implement Posix ACLs without these helpers (XFS does). |
417 | # Never use this symbol for ifdefs. | 417 | # Never use this symbol for ifdefs. |
@@ -689,6 +689,7 @@ config ZISOFS | |||
689 | 689 | ||
690 | config UDF_FS | 690 | config UDF_FS |
691 | tristate "UDF file system support" | 691 | tristate "UDF file system support" |
692 | select CRC_ITU_T | ||
692 | help | 693 | help |
693 | This is the new file system used on some CD-ROMs and DVDs. Say Y if | 694 | This is the new file system used on some CD-ROMs and DVDs. Say Y if |
694 | you intend to mount DVD discs or CDRW's written in packet mode, or | 695 | you intend to mount DVD discs or CDRW's written in packet mode, or |
@@ -1663,105 +1664,86 @@ config NFS_V4 | |||
1663 | 1664 | ||
1664 | If unsure, say N. | 1665 | If unsure, say N. |
1665 | 1666 | ||
1666 | config NFS_DIRECTIO | ||
1667 | bool "Allow direct I/O on NFS files" | ||
1668 | depends on NFS_FS | ||
1669 | help | ||
1670 | This option enables applications to perform uncached I/O on files | ||
1671 | in NFS file systems using the O_DIRECT open() flag. When O_DIRECT | ||
1672 | is set for a file, its data is not cached in the system's page | ||
1673 | cache. Data is moved to and from user-level application buffers | ||
1674 | directly. Unlike local disk-based file systems, NFS O_DIRECT has | ||
1675 | no alignment restrictions. | ||
1676 | |||
1677 | Unless your program is designed to use O_DIRECT properly, you are | ||
1678 | much better off allowing the NFS client to manage data caching for | ||
1679 | you. Misusing O_DIRECT can cause poor server performance or network | ||
1680 | storms. This kernel build option defaults OFF to avoid exposing | ||
1681 | system administrators unwittingly to a potentially hazardous | ||
1682 | feature. | ||
1683 | |||
1684 | For more details on NFS O_DIRECT, see fs/nfs/direct.c. | ||
1685 | |||
1686 | If unsure, say N. This reduces the size of the NFS client, and | ||
1687 | causes open() to return EINVAL if a file residing in NFS is | ||
1688 | opened with the O_DIRECT flag. | ||
1689 | |||
1690 | config NFSD | 1667 | config NFSD |
1691 | tristate "NFS server support" | 1668 | tristate "NFS server support" |
1692 | depends on INET | 1669 | depends on INET |
1693 | select LOCKD | 1670 | select LOCKD |
1694 | select SUNRPC | 1671 | select SUNRPC |
1695 | select EXPORTFS | 1672 | select EXPORTFS |
1696 | select NFSD_V2_ACL if NFSD_V3_ACL | ||
1697 | select NFS_ACL_SUPPORT if NFSD_V2_ACL | 1673 | select NFS_ACL_SUPPORT if NFSD_V2_ACL |
1698 | select NFSD_TCP if NFSD_V4 | 1674 | help |
1699 | select CRYPTO_MD5 if NFSD_V4 | 1675 | Choose Y here if you want to allow other computers to access |
1700 | select CRYPTO if NFSD_V4 | 1676 | files residing on this system using Sun's Network File System |
1701 | select FS_POSIX_ACL if NFSD_V4 | 1677 | protocol. To compile the NFS server support as a module, |
1702 | select PROC_FS if NFSD_V4 | 1678 | choose M here: the module will be called nfsd. |
1703 | select PROC_FS if SUNRPC_GSS | 1679 | |
1704 | help | 1680 | You may choose to use a user-space NFS server instead, in which |
1705 | If you want your Linux box to act as an NFS *server*, so that other | 1681 | case you can choose N here. |
1706 | computers on your local network which support NFS can access certain | 1682 | |
1707 | directories on your box transparently, you have two options: you can | 1683 | To export local file systems using NFS, you also need to install |
1708 | use the self-contained user space program nfsd, in which case you | 1684 | user space programs which can be found in the Linux nfs-utils |
1709 | should say N here, or you can say Y and use the kernel based NFS | 1685 | package, available from http://linux-nfs.org/. More detail about |
1710 | server. The advantage of the kernel based solution is that it is | 1686 | the Linux NFS server implementation is available via the |
1711 | faster. | 1687 | exports(5) man page. |
1712 | 1688 | ||
1713 | In either case, you will need support software; the respective | 1689 | Below you can choose which versions of the NFS protocol are |
1714 | locations are given in the file <file:Documentation/Changes> in the | 1690 | available to clients mounting the NFS server on this system. |
1715 | NFS section. | 1691 | Support for NFS version 2 (RFC 1094) is always available when |
1716 | 1692 | CONFIG_NFSD is selected. | |
1717 | If you say Y here, you will get support for version 2 of the NFS | 1693 | |
1718 | protocol (NFSv2). If you also want NFSv3, say Y to the next question | 1694 | If unsure, say N. |
1719 | as well. | ||
1720 | |||
1721 | Please read the NFS-HOWTO, available from | ||
1722 | <http://www.tldp.org/docs.html#howto>. | ||
1723 | |||
1724 | To compile the NFS server support as a module, choose M here: the | ||
1725 | module will be called nfsd. If unsure, say N. | ||
1726 | 1695 | ||
1727 | config NFSD_V2_ACL | 1696 | config NFSD_V2_ACL |
1728 | bool | 1697 | bool |
1729 | depends on NFSD | 1698 | depends on NFSD |
1730 | 1699 | ||
1731 | config NFSD_V3 | 1700 | config NFSD_V3 |
1732 | bool "Provide NFSv3 server support" | 1701 | bool "NFS server support for NFS version 3" |
1733 | depends on NFSD | 1702 | depends on NFSD |
1734 | help | 1703 | help |
1735 | If you would like to include the NFSv3 server as well as the NFSv2 | 1704 | This option enables support in your system's NFS server for |
1736 | server, say Y here. If unsure, say Y. | 1705 | version 3 of the NFS protocol (RFC 1813). |
1706 | |||
1707 | If unsure, say Y. | ||
1737 | 1708 | ||
1738 | config NFSD_V3_ACL | 1709 | config NFSD_V3_ACL |
1739 | bool "Provide server support for the NFSv3 ACL protocol extension" | 1710 | bool "NFS server support for the NFSv3 ACL protocol extension" |
1740 | depends on NFSD_V3 | 1711 | depends on NFSD_V3 |
1712 | select NFSD_V2_ACL | ||
1741 | help | 1713 | help |
1742 | Implement the NFSv3 ACL protocol extension for manipulating POSIX | 1714 | Solaris NFS servers support an auxiliary NFSv3 ACL protocol that |
1743 | Access Control Lists on exported file systems. NFS clients should | 1715 | never became an official part of the NFS version 3 protocol. |
1744 | be compiled with the NFSv3 ACL protocol extension; see the | 1716 | This protocol extension allows applications on NFS clients to |
1745 | CONFIG_NFS_V3_ACL option. If unsure, say N. | 1717 | manipulate POSIX Access Control Lists on files residing on NFS |
1718 | servers. NFS servers enforce POSIX ACLs on local files whether | ||
1719 | this protocol is available or not. | ||
1720 | |||
1721 | This option enables support in your system's NFS server for the | ||
1722 | NFSv3 ACL protocol extension allowing NFS clients to manipulate | ||
1723 | POSIX ACLs on files exported by your system's NFS server. NFS | ||
1724 | clients which support the Solaris NFSv3 ACL protocol can then | ||
1725 | access and modify ACLs on your NFS server. | ||
1726 | |||
1727 | To store ACLs on your NFS server, you also need to enable ACL- | ||
1728 | related CONFIG options for your local file systems of choice. | ||
1729 | |||
1730 | If unsure, say N. | ||
1746 | 1731 | ||
1747 | config NFSD_V4 | 1732 | config NFSD_V4 |
1748 | bool "Provide NFSv4 server support (EXPERIMENTAL)" | 1733 | bool "NFS server support for NFS version 4 (EXPERIMENTAL)" |
1749 | depends on NFSD && NFSD_V3 && EXPERIMENTAL | 1734 | depends on NFSD && PROC_FS && EXPERIMENTAL |
1735 | select NFSD_V3 | ||
1736 | select FS_POSIX_ACL | ||
1750 | select RPCSEC_GSS_KRB5 | 1737 | select RPCSEC_GSS_KRB5 |
1751 | help | 1738 | help |
1752 | If you would like to include the NFSv4 server as well as the NFSv2 | 1739 | This option enables support in your system's NFS server for |
1753 | and NFSv3 servers, say Y here. This feature is experimental, and | 1740 | version 4 of the NFS protocol (RFC 3530). |
1754 | should only be used if you are interested in helping to test NFSv4. | ||
1755 | If unsure, say N. | ||
1756 | 1741 | ||
1757 | config NFSD_TCP | 1742 | To export files using NFSv4, you need to install additional user |
1758 | bool "Provide NFS server over TCP support" | 1743 | space programs which can be found in the Linux nfs-utils package, |
1759 | depends on NFSD | 1744 | available from http://linux-nfs.org/. |
1760 | default y | 1745 | |
1761 | help | 1746 | If unsure, say N. |
1762 | If you want your NFS server to support TCP connections, say Y here. | ||
1763 | TCP connections usually perform better than the default UDP when | ||
1764 | the network is lossy or congested. If unsure, say Y. | ||
1765 | 1747 | ||
1766 | config ROOT_NFS | 1748 | config ROOT_NFS |
1767 | bool "Root file system on NFS" | 1749 | bool "Root file system on NFS" |
@@ -1807,15 +1789,33 @@ config SUNRPC_XPRT_RDMA | |||
1807 | tristate | 1789 | tristate |
1808 | depends on SUNRPC && INFINIBAND && EXPERIMENTAL | 1790 | depends on SUNRPC && INFINIBAND && EXPERIMENTAL |
1809 | default SUNRPC && INFINIBAND | 1791 | default SUNRPC && INFINIBAND |
1792 | help | ||
1793 | This option enables an RPC client transport capability that | ||
1794 | allows the NFS client to mount servers via an RDMA-enabled | ||
1795 | transport. | ||
1796 | |||
1797 | To compile RPC client RDMA transport support as a module, | ||
1798 | choose M here: the module will be called xprtrdma. | ||
1799 | |||
1800 | If unsure, say N. | ||
1810 | 1801 | ||
1811 | config SUNRPC_BIND34 | 1802 | config SUNRPC_BIND34 |
1812 | bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)" | 1803 | bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)" |
1813 | depends on SUNRPC && EXPERIMENTAL | 1804 | depends on SUNRPC && EXPERIMENTAL |
1805 | default n | ||
1814 | help | 1806 | help |
1815 | Provides kernel support for querying rpcbind servers via versions 3 | 1807 | RPC requests over IPv6 networks require support for larger |
1816 | and 4 of the rpcbind protocol. The kernel automatically falls back | 1808 | addresses when performing an RPC bind. Sun added support for |
1817 | to version 2 if a remote rpcbind service does not support versions | 1809 | IPv6 addressing by creating two new versions of the rpcbind |
1818 | 3 or 4. | 1810 | protocol (RFC 1833). |
1811 | |||
1812 | This option enables support in the kernel RPC client for | ||
1813 | querying rpcbind servers via versions 3 and 4 of the rpcbind | ||
1814 | protocol. The kernel automatically falls back to version 2 | ||
1815 | if a remote rpcbind service does not support versions 3 or 4. | ||
1816 | By themselves, these new versions do not provide support for | ||
1817 | RPC over IPv6, but the new protocol versions are necessary to | ||
1818 | support it. | ||
1819 | 1819 | ||
1820 | If unsure, say N to get traditional behavior (version 2 rpcbind | 1820 | If unsure, say N to get traditional behavior (version 2 rpcbind |
1821 | requests only). | 1821 | requests only). |
@@ -1829,12 +1829,13 @@ config RPCSEC_GSS_KRB5 | |||
1829 | select CRYPTO_DES | 1829 | select CRYPTO_DES |
1830 | select CRYPTO_CBC | 1830 | select CRYPTO_CBC |
1831 | help | 1831 | help |
1832 | Provides for secure RPC calls by means of a gss-api | 1832 | Choose Y here to enable Secure RPC using the Kerberos version 5 |
1833 | mechanism based on Kerberos V5. This is required for | 1833 | GSS-API mechanism (RFC 1964). |
1834 | NFSv4. | ||
1835 | 1834 | ||
1836 | Note: Requires an auxiliary userspace daemon which may be found on | 1835 | Secure RPC calls with Kerberos require an auxiliary user-space |
1837 | http://www.citi.umich.edu/projects/nfsv4/ | 1836 | daemon which may be found in the Linux nfs-utils package |
1837 | available from http://linux-nfs.org/. In addition, user-space | ||
1838 | Kerberos support should be installed. | ||
1838 | 1839 | ||
1839 | If unsure, say N. | 1840 | If unsure, say N. |
1840 | 1841 | ||
@@ -1848,11 +1849,12 @@ config RPCSEC_GSS_SPKM3 | |||
1848 | select CRYPTO_CAST5 | 1849 | select CRYPTO_CAST5 |
1849 | select CRYPTO_CBC | 1850 | select CRYPTO_CBC |
1850 | help | 1851 | help |
1851 | Provides for secure RPC calls by means of a gss-api | 1852 | Choose Y here to enable Secure RPC using the SPKM3 public key |
1852 | mechanism based on the SPKM3 public-key mechanism. | 1853 | GSS-API mechansim (RFC 2025). |
1853 | 1854 | ||
1854 | Note: Requires an auxiliary userspace daemon which may be found on | 1855 | Secure RPC calls with SPKM3 require an auxiliary userspace |
1855 | http://www.citi.umich.edu/projects/nfsv4/ | 1856 | daemon which may be found in the Linux nfs-utils package |
1857 | available from http://linux-nfs.org/. | ||
1856 | 1858 | ||
1857 | If unsure, say N. | 1859 | If unsure, say N. |
1858 | 1860 | ||
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 5e1a4fb5cacb..9924581df6f6 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -543,7 +543,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
543 | unsigned long interp_load_addr = 0; | 543 | unsigned long interp_load_addr = 0; |
544 | unsigned long start_code, end_code, start_data, end_data; | 544 | unsigned long start_code, end_code, start_data, end_data; |
545 | unsigned long reloc_func_desc = 0; | 545 | unsigned long reloc_func_desc = 0; |
546 | struct files_struct *files; | ||
547 | int executable_stack = EXSTACK_DEFAULT; | 546 | int executable_stack = EXSTACK_DEFAULT; |
548 | unsigned long def_flags = 0; | 547 | unsigned long def_flags = 0; |
549 | struct { | 548 | struct { |
@@ -593,20 +592,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
593 | goto out_free_ph; | 592 | goto out_free_ph; |
594 | } | 593 | } |
595 | 594 | ||
596 | files = current->files; /* Refcounted so ok */ | ||
597 | retval = unshare_files(); | ||
598 | if (retval < 0) | ||
599 | goto out_free_ph; | ||
600 | if (files == current->files) { | ||
601 | put_files_struct(files); | ||
602 | files = NULL; | ||
603 | } | ||
604 | |||
605 | /* exec will make our files private anyway, but for the a.out | ||
606 | loader stuff we need to do it earlier */ | ||
607 | retval = get_unused_fd(); | 595 | retval = get_unused_fd(); |
608 | if (retval < 0) | 596 | if (retval < 0) |
609 | goto out_free_fh; | 597 | goto out_free_ph; |
610 | get_file(bprm->file); | 598 | get_file(bprm->file); |
611 | fd_install(elf_exec_fileno = retval, bprm->file); | 599 | fd_install(elf_exec_fileno = retval, bprm->file); |
612 | 600 | ||
@@ -728,12 +716,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
728 | if (retval) | 716 | if (retval) |
729 | goto out_free_dentry; | 717 | goto out_free_dentry; |
730 | 718 | ||
731 | /* Discard our unneeded old files struct */ | ||
732 | if (files) { | ||
733 | put_files_struct(files); | ||
734 | files = NULL; | ||
735 | } | ||
736 | |||
737 | /* OK, This is the point of no return */ | 719 | /* OK, This is the point of no return */ |
738 | current->flags &= ~PF_FORKNOEXEC; | 720 | current->flags &= ~PF_FORKNOEXEC; |
739 | current->mm->def_flags = def_flags; | 721 | current->mm->def_flags = def_flags; |
@@ -1016,9 +998,6 @@ out_free_interp: | |||
1016 | kfree(elf_interpreter); | 998 | kfree(elf_interpreter); |
1017 | out_free_file: | 999 | out_free_file: |
1018 | sys_close(elf_exec_fileno); | 1000 | sys_close(elf_exec_fileno); |
1019 | out_free_fh: | ||
1020 | if (files) | ||
1021 | reset_files_struct(current, files); | ||
1022 | out_free_ph: | 1001 | out_free_ph: |
1023 | kfree(elf_phdata); | 1002 | kfree(elf_phdata); |
1024 | goto out; | 1003 | goto out; |
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index b53c7e5f41bb..dbf0ac0523de 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c | |||
@@ -110,7 +110,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
110 | char *iname_addr = iname; | 110 | char *iname_addr = iname; |
111 | int retval; | 111 | int retval; |
112 | int fd_binary = -1; | 112 | int fd_binary = -1; |
113 | struct files_struct *files = NULL; | ||
114 | 113 | ||
115 | retval = -ENOEXEC; | 114 | retval = -ENOEXEC; |
116 | if (!enabled) | 115 | if (!enabled) |
@@ -133,21 +132,13 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
133 | 132 | ||
134 | if (fmt->flags & MISC_FMT_OPEN_BINARY) { | 133 | if (fmt->flags & MISC_FMT_OPEN_BINARY) { |
135 | 134 | ||
136 | files = current->files; | ||
137 | retval = unshare_files(); | ||
138 | if (retval < 0) | ||
139 | goto _ret; | ||
140 | if (files == current->files) { | ||
141 | put_files_struct(files); | ||
142 | files = NULL; | ||
143 | } | ||
144 | /* if the binary should be opened on behalf of the | 135 | /* if the binary should be opened on behalf of the |
145 | * interpreter than keep it open and assign descriptor | 136 | * interpreter than keep it open and assign descriptor |
146 | * to it */ | 137 | * to it */ |
147 | fd_binary = get_unused_fd(); | 138 | fd_binary = get_unused_fd(); |
148 | if (fd_binary < 0) { | 139 | if (fd_binary < 0) { |
149 | retval = fd_binary; | 140 | retval = fd_binary; |
150 | goto _unshare; | 141 | goto _ret; |
151 | } | 142 | } |
152 | fd_install(fd_binary, bprm->file); | 143 | fd_install(fd_binary, bprm->file); |
153 | 144 | ||
@@ -205,10 +196,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
205 | if (retval < 0) | 196 | if (retval < 0) |
206 | goto _error; | 197 | goto _error; |
207 | 198 | ||
208 | if (files) { | ||
209 | put_files_struct(files); | ||
210 | files = NULL; | ||
211 | } | ||
212 | _ret: | 199 | _ret: |
213 | return retval; | 200 | return retval; |
214 | _error: | 201 | _error: |
@@ -216,9 +203,6 @@ _error: | |||
216 | sys_close(fd_binary); | 203 | sys_close(fd_binary); |
217 | bprm->interp_flags = 0; | 204 | bprm->interp_flags = 0; |
218 | bprm->interp_data = 0; | 205 | bprm->interp_data = 0; |
219 | _unshare: | ||
220 | if (files) | ||
221 | reset_files_struct(current, files); | ||
222 | goto _ret; | 206 | goto _ret; |
223 | } | 207 | } |
224 | 208 | ||
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c index 14c63527c762..fdc36bfd6a7b 100644 --- a/fs/binfmt_som.c +++ b/fs/binfmt_som.c | |||
@@ -194,7 +194,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
194 | unsigned long som_entry; | 194 | unsigned long som_entry; |
195 | struct som_hdr *som_ex; | 195 | struct som_hdr *som_ex; |
196 | struct som_exec_auxhdr *hpuxhdr; | 196 | struct som_exec_auxhdr *hpuxhdr; |
197 | struct files_struct *files; | ||
198 | 197 | ||
199 | /* Get the exec-header */ | 198 | /* Get the exec-header */ |
200 | som_ex = (struct som_hdr *) bprm->buf; | 199 | som_ex = (struct som_hdr *) bprm->buf; |
@@ -221,15 +220,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
221 | goto out_free; | 220 | goto out_free; |
222 | } | 221 | } |
223 | 222 | ||
224 | files = current->files; /* Refcounted so ok */ | ||
225 | retval = unshare_files(); | ||
226 | if (retval < 0) | ||
227 | goto out_free; | ||
228 | if (files == current->files) { | ||
229 | put_files_struct(files); | ||
230 | files = NULL; | ||
231 | } | ||
232 | |||
233 | retval = get_unused_fd(); | 223 | retval = get_unused_fd(); |
234 | if (retval < 0) | 224 | if (retval < 0) |
235 | goto out_free; | 225 | goto out_free; |
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index dbd91461853c..05c9da6181c3 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -8,7 +8,8 @@ of second share to disconnected server session (autoreconnect on this). | |||
8 | Add ability to modify cifs acls for handling chmod (when mounted with | 8 | Add ability to modify cifs acls for handling chmod (when mounted with |
9 | cifsacl flag). Fix prefixpath path separator so we can handle mounts | 9 | cifsacl flag). Fix prefixpath path separator so we can handle mounts |
10 | with prefixpaths longer than one directory (one path component) when | 10 | with prefixpaths longer than one directory (one path component) when |
11 | mounted to Windows servers. | 11 | mounted to Windows servers. Fix slow file open when cifsacl |
12 | enabled. | ||
12 | 13 | ||
13 | Version 1.51 | 14 | Version 1.51 |
14 | ------------ | 15 | ------------ |
diff --git a/fs/cifs/README b/fs/cifs/README index 50306229b0f9..621aa1a85971 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -3,7 +3,14 @@ features such as hierarchical dfs like namespace, hardlinks, locking and more. | |||
3 | It was designed to comply with the SNIA CIFS Technical Reference (which | 3 | It was designed to comply with the SNIA CIFS Technical Reference (which |
4 | supersedes the 1992 X/Open SMB Standard) as well as to perform best practice | 4 | supersedes the 1992 X/Open SMB Standard) as well as to perform best practice |
5 | practical interoperability with Windows 2000, Windows XP, Samba and equivalent | 5 | practical interoperability with Windows 2000, Windows XP, Samba and equivalent |
6 | servers. | 6 | servers. This code was developed in participation with the Protocol Freedom |
7 | Information Foundation. | ||
8 | |||
9 | Please see | ||
10 | http://protocolfreedom.org/ and | ||
11 | http://samba.org/samba/PFIF/ | ||
12 | for more details. | ||
13 | |||
7 | 14 | ||
8 | For questions or bug reports please contact: | 15 | For questions or bug reports please contact: |
9 | sfrench@samba.org (sfrench@us.ibm.com) | 16 | sfrench@samba.org (sfrench@us.ibm.com) |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 56c924033b78..95024c066d89 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -23,16 +23,28 @@ | |||
23 | #include "dns_resolve.h" | 23 | #include "dns_resolve.h" |
24 | #include "cifs_debug.h" | 24 | #include "cifs_debug.h" |
25 | 25 | ||
26 | LIST_HEAD(cifs_dfs_automount_list); | 26 | static LIST_HEAD(cifs_dfs_automount_list); |
27 | 27 | ||
28 | /* | 28 | static void cifs_dfs_expire_automounts(struct work_struct *work); |
29 | * DFS functions | 29 | static DECLARE_DELAYED_WORK(cifs_dfs_automount_task, |
30 | */ | 30 | cifs_dfs_expire_automounts); |
31 | static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ; | ||
32 | |||
33 | static void cifs_dfs_expire_automounts(struct work_struct *work) | ||
34 | { | ||
35 | struct list_head *list = &cifs_dfs_automount_list; | ||
36 | |||
37 | mark_mounts_for_expiry(list); | ||
38 | if (!list_empty(list)) | ||
39 | schedule_delayed_work(&cifs_dfs_automount_task, | ||
40 | cifs_dfs_mountpoint_expiry_timeout); | ||
41 | } | ||
31 | 42 | ||
32 | void dfs_shrink_umount_helper(struct vfsmount *vfsmnt) | 43 | void cifs_dfs_release_automount_timer(void) |
33 | { | 44 | { |
34 | mark_mounts_for_expiry(&cifs_dfs_automount_list); | 45 | BUG_ON(!list_empty(&cifs_dfs_automount_list)); |
35 | mark_mounts_for_expiry(&cifs_dfs_automount_list); | 46 | cancel_delayed_work(&cifs_dfs_automount_task); |
47 | flush_scheduled_work(); | ||
36 | } | 48 | } |
37 | 49 | ||
38 | /** | 50 | /** |
@@ -261,10 +273,11 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, | |||
261 | err = do_add_mount(newmnt, nd, nd->path.mnt->mnt_flags, mntlist); | 273 | err = do_add_mount(newmnt, nd, nd->path.mnt->mnt_flags, mntlist); |
262 | switch (err) { | 274 | switch (err) { |
263 | case 0: | 275 | case 0: |
264 | dput(nd->path.dentry); | 276 | path_put(&nd->path); |
265 | mntput(nd->path.mnt); | ||
266 | nd->path.mnt = newmnt; | 277 | nd->path.mnt = newmnt; |
267 | nd->path.dentry = dget(newmnt->mnt_root); | 278 | nd->path.dentry = dget(newmnt->mnt_root); |
279 | schedule_delayed_work(&cifs_dfs_automount_task, | ||
280 | cifs_dfs_mountpoint_expiry_timeout); | ||
268 | break; | 281 | break; |
269 | case -EBUSY: | 282 | case -EBUSY: |
270 | /* someone else made a mount here whilst we were busy */ | 283 | /* someone else made a mount here whilst we were busy */ |
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 1cb5b0a9f2ac..e99d4faf5f02 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
@@ -516,7 +516,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
516 | 516 | ||
517 | /* Convert permission bits from mode to equivalent CIFS ACL */ | 517 | /* Convert permission bits from mode to equivalent CIFS ACL */ |
518 | static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, | 518 | static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, |
519 | int acl_len, struct inode *inode, __u64 nmode) | 519 | struct inode *inode, __u64 nmode) |
520 | { | 520 | { |
521 | int rc = 0; | 521 | int rc = 0; |
522 | __u32 dacloffset; | 522 | __u32 dacloffset; |
@@ -692,14 +692,14 @@ void acl_to_uid_mode(struct inode *inode, const char *path, const __u16 *pfid) | |||
692 | int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) | 692 | int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) |
693 | { | 693 | { |
694 | int rc = 0; | 694 | int rc = 0; |
695 | __u32 acllen = 0; | 695 | __u32 secdesclen = 0; |
696 | struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */ | 696 | struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */ |
697 | struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */ | 697 | struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */ |
698 | 698 | ||
699 | cFYI(DBG2, ("set ACL from mode for %s", path)); | 699 | cFYI(DBG2, ("set ACL from mode for %s", path)); |
700 | 700 | ||
701 | /* Get the security descriptor */ | 701 | /* Get the security descriptor */ |
702 | pntsd = get_cifs_acl(&acllen, inode, path, NULL); | 702 | pntsd = get_cifs_acl(&secdesclen, inode, path, NULL); |
703 | 703 | ||
704 | /* Add three ACEs for owner, group, everyone getting rid of | 704 | /* Add three ACEs for owner, group, everyone getting rid of |
705 | other ACEs as chmod disables ACEs and set the security descriptor */ | 705 | other ACEs as chmod disables ACEs and set the security descriptor */ |
@@ -709,20 +709,22 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) | |||
709 | set security descriptor request security descriptor | 709 | set security descriptor request security descriptor |
710 | parameters, and secuirty descriptor itself */ | 710 | parameters, and secuirty descriptor itself */ |
711 | 711 | ||
712 | pnntsd = kmalloc(acllen, GFP_KERNEL); | 712 | secdesclen = secdesclen < DEFSECDESCLEN ? |
713 | DEFSECDESCLEN : secdesclen; | ||
714 | pnntsd = kmalloc(secdesclen, GFP_KERNEL); | ||
713 | if (!pnntsd) { | 715 | if (!pnntsd) { |
714 | cERROR(1, ("Unable to allocate security descriptor")); | 716 | cERROR(1, ("Unable to allocate security descriptor")); |
715 | kfree(pntsd); | 717 | kfree(pntsd); |
716 | return (-ENOMEM); | 718 | return (-ENOMEM); |
717 | } | 719 | } |
718 | 720 | ||
719 | rc = build_sec_desc(pntsd, pnntsd, acllen, inode, nmode); | 721 | rc = build_sec_desc(pntsd, pnntsd, inode, nmode); |
720 | 722 | ||
721 | cFYI(DBG2, ("build_sec_desc rc: %d", rc)); | 723 | cFYI(DBG2, ("build_sec_desc rc: %d", rc)); |
722 | 724 | ||
723 | if (!rc) { | 725 | if (!rc) { |
724 | /* Set the security descriptor */ | 726 | /* Set the security descriptor */ |
725 | rc = set_cifs_acl(pnntsd, acllen, inode, path); | 727 | rc = set_cifs_acl(pnntsd, secdesclen, inode, path); |
726 | cFYI(DBG2, ("set_cifs_acl rc: %d", rc)); | 728 | cFYI(DBG2, ("set_cifs_acl rc: %d", rc)); |
727 | } | 729 | } |
728 | 730 | ||
diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 93a7c3462ea2..6c8096cf5155 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h | |||
@@ -27,6 +27,7 @@ | |||
27 | #define NUM_SUBAUTHS 5 /* number of sub authority fields */ | 27 | #define NUM_SUBAUTHS 5 /* number of sub authority fields */ |
28 | #define NUM_WK_SIDS 7 /* number of well known sids */ | 28 | #define NUM_WK_SIDS 7 /* number of well known sids */ |
29 | #define SIDNAMELENGTH 20 /* long enough for the ones we care about */ | 29 | #define SIDNAMELENGTH 20 /* long enough for the ones we care about */ |
30 | #define DEFSECDESCLEN 192 /* sec desc len contaiting a dacl with three aces */ | ||
30 | 31 | ||
31 | #define READ_BIT 0x4 | 32 | #define READ_BIT 0x4 |
32 | #define WRITE_BIT 0x2 | 33 | #define WRITE_BIT 0x2 |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index a04b17e5a9d0..39c2cbdface7 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -466,16 +466,11 @@ static struct quotactl_ops cifs_quotactl_ops = { | |||
466 | }; | 466 | }; |
467 | #endif | 467 | #endif |
468 | 468 | ||
469 | static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags) | 469 | static void cifs_umount_begin(struct super_block *sb) |
470 | { | 470 | { |
471 | struct cifs_sb_info *cifs_sb; | 471 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
472 | struct cifsTconInfo *tcon; | 472 | struct cifsTconInfo *tcon; |
473 | 473 | ||
474 | dfs_shrink_umount_helper(vfsmnt); | ||
475 | |||
476 | if (!(flags & MNT_FORCE)) | ||
477 | return; | ||
478 | cifs_sb = CIFS_SB(vfsmnt->mnt_sb); | ||
479 | if (cifs_sb == NULL) | 474 | if (cifs_sb == NULL) |
480 | return; | 475 | return; |
481 | 476 | ||
@@ -1100,6 +1095,7 @@ exit_cifs(void) | |||
1100 | cFYI(DBG2, ("exit_cifs")); | 1095 | cFYI(DBG2, ("exit_cifs")); |
1101 | cifs_proc_clean(); | 1096 | cifs_proc_clean(); |
1102 | #ifdef CONFIG_CIFS_DFS_UPCALL | 1097 | #ifdef CONFIG_CIFS_DFS_UPCALL |
1098 | cifs_dfs_release_automount_timer(); | ||
1103 | unregister_key_type(&key_type_dns_resolver); | 1099 | unregister_key_type(&key_type_dns_resolver); |
1104 | #endif | 1100 | #endif |
1105 | #ifdef CONFIG_CIFS_UPCALL | 1101 | #ifdef CONFIG_CIFS_UPCALL |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 68978306c3ca..e1dd9f32e1d7 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -62,11 +62,9 @@ extern int cifs_setattr(struct dentry *, struct iattr *); | |||
62 | 62 | ||
63 | extern const struct inode_operations cifs_file_inode_ops; | 63 | extern const struct inode_operations cifs_file_inode_ops; |
64 | extern const struct inode_operations cifs_symlink_inode_ops; | 64 | extern const struct inode_operations cifs_symlink_inode_ops; |
65 | extern struct list_head cifs_dfs_automount_list; | ||
66 | extern struct inode_operations cifs_dfs_referral_inode_operations; | 65 | extern struct inode_operations cifs_dfs_referral_inode_operations; |
67 | 66 | ||
68 | 67 | ||
69 | |||
70 | /* Functions related to files and directories */ | 68 | /* Functions related to files and directories */ |
71 | extern const struct file_operations cifs_file_ops; | 69 | extern const struct file_operations cifs_file_ops; |
72 | extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */ | 70 | extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */ |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 47f79504f57b..9f49c2f3582c 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * fs/cifs/cifspdu.h | 2 | * fs/cifs/cifspdu.h |
3 | * | 3 | * |
4 | * Copyright (c) International Business Machines Corp., 2002,2007 | 4 | * Copyright (c) International Business Machines Corp., 2002,2008 |
5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * | 6 | * |
7 | * This library is free software; you can redistribute it and/or modify | 7 | * This library is free software; you can redistribute it and/or modify |
@@ -163,7 +163,10 @@ | |||
163 | path names in response */ | 163 | path names in response */ |
164 | #define SMBFLG2_KNOWS_EAS cpu_to_le16(2) | 164 | #define SMBFLG2_KNOWS_EAS cpu_to_le16(2) |
165 | #define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4) | 165 | #define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4) |
166 | #define SMBFLG2_COMPRESSED (8) | ||
167 | #define SMBFLG2_SECURITY_SIGNATURE_REQUIRED (0x10) | ||
166 | #define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40) | 168 | #define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40) |
169 | #define SMBFLG2_REPARSE_PATH (0x400) | ||
167 | #define SMBFLG2_EXT_SEC cpu_to_le16(0x800) | 170 | #define SMBFLG2_EXT_SEC cpu_to_le16(0x800) |
168 | #define SMBFLG2_DFS cpu_to_le16(0x1000) | 171 | #define SMBFLG2_DFS cpu_to_le16(0x1000) |
169 | #define SMBFLG2_PAGING_IO cpu_to_le16(0x2000) | 172 | #define SMBFLG2_PAGING_IO cpu_to_le16(0x2000) |
@@ -305,7 +308,7 @@ | |||
305 | #define FILE_SHARE_DELETE 0x00000004 | 308 | #define FILE_SHARE_DELETE 0x00000004 |
306 | #define FILE_SHARE_ALL 0x00000007 | 309 | #define FILE_SHARE_ALL 0x00000007 |
307 | 310 | ||
308 | /* CreateDisposition flags */ | 311 | /* CreateDisposition flags, similar to CreateAction as well */ |
309 | #define FILE_SUPERSEDE 0x00000000 | 312 | #define FILE_SUPERSEDE 0x00000000 |
310 | #define FILE_OPEN 0x00000001 | 313 | #define FILE_OPEN 0x00000001 |
311 | #define FILE_CREATE 0x00000002 | 314 | #define FILE_CREATE 0x00000002 |
@@ -317,15 +320,25 @@ | |||
317 | #define CREATE_NOT_FILE 0x00000001 /* if set must not be file */ | 320 | #define CREATE_NOT_FILE 0x00000001 /* if set must not be file */ |
318 | #define CREATE_WRITE_THROUGH 0x00000002 | 321 | #define CREATE_WRITE_THROUGH 0x00000002 |
319 | #define CREATE_SEQUENTIAL 0x00000004 | 322 | #define CREATE_SEQUENTIAL 0x00000004 |
320 | #define CREATE_SYNC_ALERT 0x00000010 | 323 | #define CREATE_NO_BUFFER 0x00000008 /* should not buffer on srv */ |
321 | #define CREATE_ASYNC_ALERT 0x00000020 | 324 | #define CREATE_SYNC_ALERT 0x00000010 /* MBZ */ |
325 | #define CREATE_ASYNC_ALERT 0x00000020 /* MBZ */ | ||
322 | #define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */ | 326 | #define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */ |
327 | #define CREATE_TREE_CONNECTION 0x00000080 /* should be zero */ | ||
328 | #define CREATE_COMPLETE_IF_OPLK 0x00000100 /* should be zero */ | ||
323 | #define CREATE_NO_EA_KNOWLEDGE 0x00000200 | 329 | #define CREATE_NO_EA_KNOWLEDGE 0x00000200 |
324 | #define CREATE_EIGHT_DOT_THREE 0x00000400 | 330 | #define CREATE_EIGHT_DOT_THREE 0x00000400 /* doc says this is obsolete |
331 | open for recovery flag - should | ||
332 | be zero */ | ||
325 | #define CREATE_RANDOM_ACCESS 0x00000800 | 333 | #define CREATE_RANDOM_ACCESS 0x00000800 |
326 | #define CREATE_DELETE_ON_CLOSE 0x00001000 | 334 | #define CREATE_DELETE_ON_CLOSE 0x00001000 |
327 | #define CREATE_OPEN_BY_ID 0x00002000 | 335 | #define CREATE_OPEN_BY_ID 0x00002000 |
336 | #define CREATE_OPEN_BACKUP_INTN 0x00004000 | ||
337 | #define CREATE_NO_COMPRESSION 0x00008000 | ||
338 | #define CREATE_RESERVE_OPFILTER 0x00100000 /* should be zero */ | ||
328 | #define OPEN_REPARSE_POINT 0x00200000 | 339 | #define OPEN_REPARSE_POINT 0x00200000 |
340 | #define OPEN_NO_RECALL 0x00400000 | ||
341 | #define OPEN_FREE_SPACE_QUERY 0x00800000 /* should be zero */ | ||
329 | #define CREATE_OPTIONS_MASK 0x007FFFFF | 342 | #define CREATE_OPTIONS_MASK 0x007FFFFF |
330 | #define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */ | 343 | #define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */ |
331 | 344 | ||
@@ -470,7 +483,7 @@ typedef struct lanman_neg_rsp { | |||
470 | 483 | ||
471 | typedef struct negotiate_rsp { | 484 | typedef struct negotiate_rsp { |
472 | struct smb_hdr hdr; /* wct = 17 */ | 485 | struct smb_hdr hdr; /* wct = 17 */ |
473 | __le16 DialectIndex; | 486 | __le16 DialectIndex; /* 0xFFFF = no dialect acceptable */ |
474 | __u8 SecurityMode; | 487 | __u8 SecurityMode; |
475 | __le16 MaxMpxCount; | 488 | __le16 MaxMpxCount; |
476 | __le16 MaxNumberVcs; | 489 | __le16 MaxNumberVcs; |
@@ -516,10 +529,11 @@ typedef struct negotiate_rsp { | |||
516 | #define CAP_INFOLEVEL_PASSTHRU 0x00002000 | 529 | #define CAP_INFOLEVEL_PASSTHRU 0x00002000 |
517 | #define CAP_LARGE_READ_X 0x00004000 | 530 | #define CAP_LARGE_READ_X 0x00004000 |
518 | #define CAP_LARGE_WRITE_X 0x00008000 | 531 | #define CAP_LARGE_WRITE_X 0x00008000 |
532 | #define CAP_LWIO 0x00010000 /* support fctl_srv_req_resume_key */ | ||
519 | #define CAP_UNIX 0x00800000 | 533 | #define CAP_UNIX 0x00800000 |
520 | #define CAP_RESERVED 0x02000000 | 534 | #define CAP_COMPRESSED_DATA 0x02000000 |
521 | #define CAP_BULK_TRANSFER 0x20000000 | 535 | #define CAP_DYNAMIC_REAUTH 0x20000000 |
522 | #define CAP_COMPRESSED_DATA 0x40000000 | 536 | #define CAP_PERSISTENT_HANDLES 0x40000000 |
523 | #define CAP_EXTENDED_SECURITY 0x80000000 | 537 | #define CAP_EXTENDED_SECURITY 0x80000000 |
524 | 538 | ||
525 | typedef union smb_com_session_setup_andx { | 539 | typedef union smb_com_session_setup_andx { |
@@ -668,9 +682,7 @@ typedef struct smb_com_tconx_req { | |||
668 | } __attribute__((packed)) TCONX_REQ; | 682 | } __attribute__((packed)) TCONX_REQ; |
669 | 683 | ||
670 | typedef struct smb_com_tconx_rsp { | 684 | typedef struct smb_com_tconx_rsp { |
671 | struct smb_hdr hdr; /* wct = 3 note that Win2000 has sent wct = 7 | 685 | struct smb_hdr hdr; /* wct = 3 , not extended response */ |
672 | in some cases on responses. Four unspecified | ||
673 | words followed OptionalSupport */ | ||
674 | __u8 AndXCommand; | 686 | __u8 AndXCommand; |
675 | __u8 AndXReserved; | 687 | __u8 AndXReserved; |
676 | __le16 AndXOffset; | 688 | __le16 AndXOffset; |
@@ -680,13 +692,48 @@ typedef struct smb_com_tconx_rsp { | |||
680 | /* STRING NativeFileSystem */ | 692 | /* STRING NativeFileSystem */ |
681 | } __attribute__((packed)) TCONX_RSP; | 693 | } __attribute__((packed)) TCONX_RSP; |
682 | 694 | ||
695 | typedef struct smb_com_tconx_rsp_ext { | ||
696 | struct smb_hdr hdr; /* wct = 7, extended response */ | ||
697 | __u8 AndXCommand; | ||
698 | __u8 AndXReserved; | ||
699 | __le16 AndXOffset; | ||
700 | __le16 OptionalSupport; /* see below */ | ||
701 | __le32 MaximalShareAccessRights; | ||
702 | __le32 GuestMaximalShareAccessRights; | ||
703 | __u16 ByteCount; | ||
704 | unsigned char Service[1]; /* always ASCII, not Unicode */ | ||
705 | /* STRING NativeFileSystem */ | ||
706 | } __attribute__((packed)) TCONX_RSP_EXT; | ||
707 | |||
708 | |||
683 | /* tree connect Flags */ | 709 | /* tree connect Flags */ |
684 | #define DISCONNECT_TID 0x0001 | 710 | #define DISCONNECT_TID 0x0001 |
711 | #define TCON_EXTENDED_SIGNATURES 0x0004 | ||
685 | #define TCON_EXTENDED_SECINFO 0x0008 | 712 | #define TCON_EXTENDED_SECINFO 0x0008 |
713 | |||
686 | /* OptionalSupport bits */ | 714 | /* OptionalSupport bits */ |
687 | #define SMB_SUPPORT_SEARCH_BITS 0x0001 /* "must have" directory search bits | 715 | #define SMB_SUPPORT_SEARCH_BITS 0x0001 /* "must have" directory search bits |
688 | (exclusive searches supported) */ | 716 | (exclusive searches supported) */ |
689 | #define SMB_SHARE_IS_IN_DFS 0x0002 | 717 | #define SMB_SHARE_IS_IN_DFS 0x0002 |
718 | #define SMB_CSC_MASK 0x000C | ||
719 | /* CSC flags defined as follows */ | ||
720 | #define SMB_CSC_CACHE_MANUAL_REINT 0x0000 | ||
721 | #define SMB_CSC_CACHE_AUTO_REINT 0x0004 | ||
722 | #define SMB_CSC_CACHE_VDO 0x0008 | ||
723 | #define SMB_CSC_NO_CACHING 0x000C | ||
724 | |||
725 | #define SMB_UNIQUE_FILE_NAME 0x0010 | ||
726 | #define SMB_EXTENDED_SIGNATURES 0x0020 | ||
727 | |||
728 | /* services | ||
729 | * | ||
730 | * A: ie disk | ||
731 | * LPT1: ie printer | ||
732 | * IPC ie named pipe | ||
733 | * COMM | ||
734 | * ????? ie any type | ||
735 | * | ||
736 | */ | ||
690 | 737 | ||
691 | typedef struct smb_com_logoff_andx_req { | 738 | typedef struct smb_com_logoff_andx_req { |
692 | struct smb_hdr hdr; /* wct = 2 */ | 739 | struct smb_hdr hdr; /* wct = 2 */ |
@@ -750,6 +797,17 @@ typedef struct smb_com_findclose_req { | |||
750 | #define COMM_DEV_TYPE 0x0004 | 797 | #define COMM_DEV_TYPE 0x0004 |
751 | #define UNKNOWN_TYPE 0xFFFF | 798 | #define UNKNOWN_TYPE 0xFFFF |
752 | 799 | ||
800 | /* Device Type or File Status Flags */ | ||
801 | #define NO_EAS 0x0001 | ||
802 | #define NO_SUBSTREAMS 0x0002 | ||
803 | #define NO_REPARSETAG 0x0004 | ||
804 | /* following flags can apply if pipe */ | ||
805 | #define ICOUNT_MASK 0x00FF | ||
806 | #define PIPE_READ_MODE 0x0100 | ||
807 | #define NAMED_PIPE_TYPE 0x0400 | ||
808 | #define PIPE_END_POINT 0x0800 | ||
809 | #define BLOCKING_NAMED_PIPE 0x8000 | ||
810 | |||
753 | typedef struct smb_com_open_req { /* also handles create */ | 811 | typedef struct smb_com_open_req { /* also handles create */ |
754 | struct smb_hdr hdr; /* wct = 24 */ | 812 | struct smb_hdr hdr; /* wct = 24 */ |
755 | __u8 AndXCommand; | 813 | __u8 AndXCommand; |
@@ -758,7 +816,7 @@ typedef struct smb_com_open_req { /* also handles create */ | |||
758 | __u8 Reserved; /* Must Be Zero */ | 816 | __u8 Reserved; /* Must Be Zero */ |
759 | __le16 NameLength; | 817 | __le16 NameLength; |
760 | __le32 OpenFlags; | 818 | __le32 OpenFlags; |
761 | __le32 RootDirectoryFid; | 819 | __u32 RootDirectoryFid; |
762 | __le32 DesiredAccess; | 820 | __le32 DesiredAccess; |
763 | __le64 AllocationSize; | 821 | __le64 AllocationSize; |
764 | __le32 FileAttributes; | 822 | __le32 FileAttributes; |
@@ -801,6 +859,32 @@ typedef struct smb_com_open_rsp { | |||
801 | __u16 ByteCount; /* bct = 0 */ | 859 | __u16 ByteCount; /* bct = 0 */ |
802 | } __attribute__((packed)) OPEN_RSP; | 860 | } __attribute__((packed)) OPEN_RSP; |
803 | 861 | ||
862 | typedef struct smb_com_open_rsp_ext { | ||
863 | struct smb_hdr hdr; /* wct = 42 but meaningless due to MS bug? */ | ||
864 | __u8 AndXCommand; | ||
865 | __u8 AndXReserved; | ||
866 | __le16 AndXOffset; | ||
867 | __u8 OplockLevel; | ||
868 | __u16 Fid; | ||
869 | __le32 CreateAction; | ||
870 | __le64 CreationTime; | ||
871 | __le64 LastAccessTime; | ||
872 | __le64 LastWriteTime; | ||
873 | __le64 ChangeTime; | ||
874 | __le32 FileAttributes; | ||
875 | __le64 AllocationSize; | ||
876 | __le64 EndOfFile; | ||
877 | __le16 FileType; | ||
878 | __le16 DeviceState; | ||
879 | __u8 DirectoryFlag; | ||
880 | __u8 VolumeGUID[16]; | ||
881 | __u64 FileId; /* note no endian conversion - is opaque UniqueID */ | ||
882 | __le32 MaximalAccessRights; | ||
883 | __le32 GuestMaximalAccessRights; | ||
884 | __u16 ByteCount; /* bct = 0 */ | ||
885 | } __attribute__((packed)) OPEN_RSP_EXT; | ||
886 | |||
887 | |||
804 | /* format of legacy open request */ | 888 | /* format of legacy open request */ |
805 | typedef struct smb_com_openx_req { | 889 | typedef struct smb_com_openx_req { |
806 | struct smb_hdr hdr; /* wct = 15 */ | 890 | struct smb_hdr hdr; /* wct = 15 */ |
@@ -1703,6 +1787,12 @@ typedef struct smb_com_transaction2_fnext_rsp_parms { | |||
1703 | #define SMB_QUERY_CIFS_UNIX_INFO 0x200 | 1787 | #define SMB_QUERY_CIFS_UNIX_INFO 0x200 |
1704 | #define SMB_QUERY_POSIX_FS_INFO 0x201 | 1788 | #define SMB_QUERY_POSIX_FS_INFO 0x201 |
1705 | #define SMB_QUERY_POSIX_WHO_AM_I 0x202 | 1789 | #define SMB_QUERY_POSIX_WHO_AM_I 0x202 |
1790 | #define SMB_REQUEST_TRANSPORT_ENCRYPTION 0x203 | ||
1791 | #define SMB_QUERY_FS_PROXY 0x204 /* WAFS enabled. Returns structure | ||
1792 | FILE_SYSTEM__UNIX_INFO to tell | ||
1793 | whether new NTIOCTL available | ||
1794 | (0xACE) for WAN friendly SMB | ||
1795 | operations to be carried */ | ||
1706 | #define SMB_QUERY_LABEL_INFO 0x3ea | 1796 | #define SMB_QUERY_LABEL_INFO 0x3ea |
1707 | #define SMB_QUERY_FS_QUOTA_INFO 0x3ee | 1797 | #define SMB_QUERY_FS_QUOTA_INFO 0x3ee |
1708 | #define SMB_QUERY_FS_FULL_SIZE_INFO 0x3ef | 1798 | #define SMB_QUERY_FS_FULL_SIZE_INFO 0x3ef |
@@ -1959,7 +2049,10 @@ typedef struct { | |||
1959 | #define CIFS_UNIX_LARGE_READ_CAP 0x00000040 /* support reads >128K (up | 2049 | #define CIFS_UNIX_LARGE_READ_CAP 0x00000040 /* support reads >128K (up |
1960 | to 0xFFFF00 */ | 2050 | to 0xFFFF00 */ |
1961 | #define CIFS_UNIX_LARGE_WRITE_CAP 0x00000080 | 2051 | #define CIFS_UNIX_LARGE_WRITE_CAP 0x00000080 |
1962 | 2052 | #define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x00000100 /* can do SPNEGO crypt */ | |
2053 | #define CIFS_UNIX_TRANPSORT_ENCRYPTION_MANDATORY_CAP 0x00000200 /* must do */ | ||
2054 | #define CIFS_UNIX_PROXY_CAP 0x00000400 /* Proxy cap: 0xACE ioctl and | ||
2055 | QFS PROXY call */ | ||
1963 | #ifdef CONFIG_CIFS_POSIX | 2056 | #ifdef CONFIG_CIFS_POSIX |
1964 | /* Can not set pathnames cap yet until we send new posix create SMB since | 2057 | /* Can not set pathnames cap yet until we send new posix create SMB since |
1965 | otherwise server can treat such handles opened with older ntcreatex | 2058 | otherwise server can treat such handles opened with older ntcreatex |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7e5e0e78cd72..50f9fdae19b3 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -84,6 +84,7 @@ extern __u16 GetNextMid(struct TCP_Server_Info *server); | |||
84 | extern struct oplock_q_entry *AllocOplockQEntry(struct inode *, u16, | 84 | extern struct oplock_q_entry *AllocOplockQEntry(struct inode *, u16, |
85 | struct cifsTconInfo *); | 85 | struct cifsTconInfo *); |
86 | extern void DeleteOplockQEntry(struct oplock_q_entry *); | 86 | extern void DeleteOplockQEntry(struct oplock_q_entry *); |
87 | extern void DeleteTconOplockQEntries(struct cifsTconInfo *); | ||
87 | extern struct timespec cifs_NTtimeToUnix(u64 utc_nanoseconds_since_1601); | 88 | extern struct timespec cifs_NTtimeToUnix(u64 utc_nanoseconds_since_1601); |
88 | extern u64 cifs_UnixTimeToNT(struct timespec); | 89 | extern u64 cifs_UnixTimeToNT(struct timespec); |
89 | extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time); | 90 | extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time); |
@@ -103,13 +104,7 @@ extern int mode_to_acl(struct inode *inode, const char *path, __u64); | |||
103 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, | 104 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, |
104 | const char *); | 105 | const char *); |
105 | extern int cifs_umount(struct super_block *, struct cifs_sb_info *); | 106 | extern int cifs_umount(struct super_block *, struct cifs_sb_info *); |
106 | #ifdef CONFIG_CIFS_DFS_UPCALL | 107 | extern void cifs_dfs_release_automount_timer(void); |
107 | extern void dfs_shrink_umount_helper(struct vfsmount *vfsmnt); | ||
108 | #else | ||
109 | static inline void dfs_shrink_umount_helper(struct vfsmount *vfsmnt) | ||
110 | { | ||
111 | } | ||
112 | #endif /* DFS_UPCALL */ | ||
113 | void cifs_proc_init(void); | 108 | void cifs_proc_init(void); |
114 | void cifs_proc_clean(void); | 109 | void cifs_proc_clean(void); |
115 | 110 | ||
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 30bbe448e260..4728fa982a4e 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -165,17 +165,19 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
165 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, | 165 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, |
166 | tcon, nls_codepage); | 166 | tcon, nls_codepage); |
167 | up(&tcon->ses->sesSem); | 167 | up(&tcon->ses->sesSem); |
168 | /* tell server which Unix caps we support */ | ||
169 | if (tcon->ses->capabilities & CAP_UNIX) | ||
170 | reset_cifs_unix_caps(0 /* no xid */, | ||
171 | tcon, | ||
172 | NULL /* we do not know sb */, | ||
173 | NULL /* no vol info */); | ||
174 | /* BB FIXME add code to check if wsize needs | 168 | /* BB FIXME add code to check if wsize needs |
175 | update due to negotiated smb buffer size | 169 | update due to negotiated smb buffer size |
176 | shrinking */ | 170 | shrinking */ |
177 | if (rc == 0) | 171 | if (rc == 0) { |
178 | atomic_inc(&tconInfoReconnectCount); | 172 | atomic_inc(&tconInfoReconnectCount); |
173 | /* tell server Unix caps we support */ | ||
174 | if (tcon->ses->capabilities & CAP_UNIX) | ||
175 | reset_cifs_unix_caps( | ||
176 | 0 /* no xid */, | ||
177 | tcon, | ||
178 | NULL /* we do not know sb */, | ||
179 | NULL /* no vol info */); | ||
180 | } | ||
179 | 181 | ||
180 | cFYI(1, ("reconnect tcon rc = %d", rc)); | 182 | cFYI(1, ("reconnect tcon rc = %d", rc)); |
181 | /* Removed call to reopen open files here. | 183 | /* Removed call to reopen open files here. |
@@ -310,17 +312,19 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
310 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, | 312 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, |
311 | tcon, nls_codepage); | 313 | tcon, nls_codepage); |
312 | up(&tcon->ses->sesSem); | 314 | up(&tcon->ses->sesSem); |
313 | /* tell server which Unix caps we support */ | ||
314 | if (tcon->ses->capabilities & CAP_UNIX) | ||
315 | reset_cifs_unix_caps(0 /* no xid */, | ||
316 | tcon, | ||
317 | NULL /* do not know sb */, | ||
318 | NULL /* no vol info */); | ||
319 | /* BB FIXME add code to check if wsize needs | 315 | /* BB FIXME add code to check if wsize needs |
320 | update due to negotiated smb buffer size | 316 | update due to negotiated smb buffer size |
321 | shrinking */ | 317 | shrinking */ |
322 | if (rc == 0) | 318 | if (rc == 0) { |
323 | atomic_inc(&tconInfoReconnectCount); | 319 | atomic_inc(&tconInfoReconnectCount); |
320 | /* tell server Unix caps we support */ | ||
321 | if (tcon->ses->capabilities & CAP_UNIX) | ||
322 | reset_cifs_unix_caps( | ||
323 | 0 /* no xid */, | ||
324 | tcon, | ||
325 | NULL /* do not know sb */, | ||
326 | NULL /* no vol info */); | ||
327 | } | ||
324 | 328 | ||
325 | cFYI(1, ("reconnect tcon rc = %d", rc)); | 329 | cFYI(1, ("reconnect tcon rc = %d", rc)); |
326 | /* Removed call to reopen open files here. | 330 | /* Removed call to reopen open files here. |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8dbfa97cd18c..e17106730168 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -3527,6 +3527,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | |||
3527 | FreeXid(xid); | 3527 | FreeXid(xid); |
3528 | return 0; | 3528 | return 0; |
3529 | } | 3529 | } |
3530 | DeleteTconOplockQEntries(cifs_sb->tcon); | ||
3530 | tconInfoFree(cifs_sb->tcon); | 3531 | tconInfoFree(cifs_sb->tcon); |
3531 | if ((ses) && (ses->server)) { | 3532 | if ((ses) && (ses->server)) { |
3532 | /* save off task so we do not refer to ses later */ | 3533 | /* save off task so we do not refer to ses later */ |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index bc673c8c1e6b..e1031b9e2c55 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -161,12 +161,14 @@ static void cifs_unix_info_to_inode(struct inode *inode, | |||
161 | spin_unlock(&inode->i_lock); | 161 | spin_unlock(&inode->i_lock); |
162 | } | 162 | } |
163 | 163 | ||
164 | static const unsigned char *cifs_get_search_path(struct cifsTconInfo *pTcon, | 164 | static const unsigned char *cifs_get_search_path(struct cifs_sb_info *cifs_sb, |
165 | const char *search_path) | 165 | const char *search_path) |
166 | { | 166 | { |
167 | int tree_len; | 167 | int tree_len; |
168 | int path_len; | 168 | int path_len; |
169 | int i; | ||
169 | char *tmp_path; | 170 | char *tmp_path; |
171 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
170 | 172 | ||
171 | if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS)) | 173 | if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS)) |
172 | return search_path; | 174 | return search_path; |
@@ -180,6 +182,11 @@ static const unsigned char *cifs_get_search_path(struct cifsTconInfo *pTcon, | |||
180 | return search_path; | 182 | return search_path; |
181 | 183 | ||
182 | strncpy(tmp_path, pTcon->treeName, tree_len); | 184 | strncpy(tmp_path, pTcon->treeName, tree_len); |
185 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) | ||
186 | for (i = 0; i < tree_len; i++) { | ||
187 | if (tmp_path[i] == '\\') | ||
188 | tmp_path[i] = '/'; | ||
189 | } | ||
183 | strncpy(tmp_path+tree_len, search_path, path_len); | 190 | strncpy(tmp_path+tree_len, search_path, path_len); |
184 | tmp_path[tree_len+path_len] = 0; | 191 | tmp_path[tree_len+path_len] = 0; |
185 | return tmp_path; | 192 | return tmp_path; |
@@ -199,7 +206,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
199 | pTcon = cifs_sb->tcon; | 206 | pTcon = cifs_sb->tcon; |
200 | cFYI(1, ("Getting info on %s", search_path)); | 207 | cFYI(1, ("Getting info on %s", search_path)); |
201 | 208 | ||
202 | full_path = cifs_get_search_path(pTcon, search_path); | 209 | full_path = cifs_get_search_path(cifs_sb, search_path); |
203 | 210 | ||
204 | try_again_CIFSSMBUnixQPathInfo: | 211 | try_again_CIFSSMBUnixQPathInfo: |
205 | /* could have done a find first instead but this returns more info */ | 212 | /* could have done a find first instead but this returns more info */ |
@@ -402,7 +409,7 @@ int cifs_get_inode_info(struct inode **pinode, | |||
402 | return -ENOMEM; | 409 | return -ENOMEM; |
403 | pfindData = (FILE_ALL_INFO *)buf; | 410 | pfindData = (FILE_ALL_INFO *)buf; |
404 | 411 | ||
405 | full_path = cifs_get_search_path(pTcon, search_path); | 412 | full_path = cifs_get_search_path(cifs_sb, search_path); |
406 | 413 | ||
407 | try_again_CIFSSMBQPathInfo: | 414 | try_again_CIFSSMBQPathInfo: |
408 | /* could do find first instead but this returns more info */ | 415 | /* could do find first instead but this returns more info */ |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 3612d6c0a0bb..000ac509c98a 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -142,6 +142,24 @@ void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry) | |||
142 | kmem_cache_free(cifs_oplock_cachep, oplockEntry); | 142 | kmem_cache_free(cifs_oplock_cachep, oplockEntry); |
143 | } | 143 | } |
144 | 144 | ||
145 | |||
146 | void DeleteTconOplockQEntries(struct cifsTconInfo *tcon) | ||
147 | { | ||
148 | struct oplock_q_entry *temp; | ||
149 | |||
150 | if (tcon == NULL) | ||
151 | return; | ||
152 | |||
153 | spin_lock(&GlobalMid_Lock); | ||
154 | list_for_each_entry(temp, &GlobalOplock_Q, qhead) { | ||
155 | if ((temp->tcon) && (temp->tcon == tcon)) { | ||
156 | list_del(&temp->qhead); | ||
157 | kmem_cache_free(cifs_oplock_cachep, temp); | ||
158 | } | ||
159 | } | ||
160 | spin_unlock(&GlobalMid_Lock); | ||
161 | } | ||
162 | |||
145 | int | 163 | int |
146 | smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | 164 | smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, |
147 | unsigned int smb_buf_length, struct sockaddr *sin) | 165 | unsigned int smb_buf_length, struct sockaddr *sin) |
diff --git a/fs/dcache.c b/fs/dcache.c index 43455776711e..3ee588d5f585 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -1746,12 +1746,21 @@ shouldnt_be_hashed: | |||
1746 | goto shouldnt_be_hashed; | 1746 | goto shouldnt_be_hashed; |
1747 | } | 1747 | } |
1748 | 1748 | ||
1749 | static int prepend(char **buffer, int *buflen, const char *str, | ||
1750 | int namelen) | ||
1751 | { | ||
1752 | *buflen -= namelen; | ||
1753 | if (*buflen < 0) | ||
1754 | return -ENAMETOOLONG; | ||
1755 | *buffer -= namelen; | ||
1756 | memcpy(*buffer, str, namelen); | ||
1757 | return 0; | ||
1758 | } | ||
1759 | |||
1749 | /** | 1760 | /** |
1750 | * d_path - return the path of a dentry | 1761 | * d_path - return the path of a dentry |
1751 | * @dentry: dentry to report | 1762 | * @path: the dentry/vfsmount to report |
1752 | * @vfsmnt: vfsmnt to which the dentry belongs | 1763 | * @root: root vfsmnt/dentry (may be modified by this function) |
1753 | * @root: root dentry | ||
1754 | * @rootmnt: vfsmnt to which the root dentry belongs | ||
1755 | * @buffer: buffer to return value in | 1764 | * @buffer: buffer to return value in |
1756 | * @buflen: buffer length | 1765 | * @buflen: buffer length |
1757 | * | 1766 | * |
@@ -1761,23 +1770,22 @@ shouldnt_be_hashed: | |||
1761 | * Returns the buffer or an error code if the path was too long. | 1770 | * Returns the buffer or an error code if the path was too long. |
1762 | * | 1771 | * |
1763 | * "buflen" should be positive. Caller holds the dcache_lock. | 1772 | * "buflen" should be positive. Caller holds the dcache_lock. |
1773 | * | ||
1774 | * If path is not reachable from the supplied root, then the value of | ||
1775 | * root is changed (without modifying refcounts). | ||
1764 | */ | 1776 | */ |
1765 | static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | 1777 | char *__d_path(const struct path *path, struct path *root, |
1766 | struct path *root, char *buffer, int buflen) | 1778 | char *buffer, int buflen) |
1767 | { | 1779 | { |
1780 | struct dentry *dentry = path->dentry; | ||
1781 | struct vfsmount *vfsmnt = path->mnt; | ||
1768 | char * end = buffer+buflen; | 1782 | char * end = buffer+buflen; |
1769 | char * retval; | 1783 | char * retval; |
1770 | int namelen; | 1784 | |
1771 | 1785 | prepend(&end, &buflen, "\0", 1); | |
1772 | *--end = '\0'; | 1786 | if (!IS_ROOT(dentry) && d_unhashed(dentry) && |
1773 | buflen--; | 1787 | (prepend(&end, &buflen, " (deleted)", 10) != 0)) |
1774 | if (!IS_ROOT(dentry) && d_unhashed(dentry)) { | ||
1775 | buflen -= 10; | ||
1776 | end -= 10; | ||
1777 | if (buflen < 0) | ||
1778 | goto Elong; | 1788 | goto Elong; |
1779 | memcpy(end, " (deleted)", 10); | ||
1780 | } | ||
1781 | 1789 | ||
1782 | if (buflen < 1) | 1790 | if (buflen < 1) |
1783 | goto Elong; | 1791 | goto Elong; |
@@ -1804,13 +1812,10 @@ static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | |||
1804 | } | 1812 | } |
1805 | parent = dentry->d_parent; | 1813 | parent = dentry->d_parent; |
1806 | prefetch(parent); | 1814 | prefetch(parent); |
1807 | namelen = dentry->d_name.len; | 1815 | if ((prepend(&end, &buflen, dentry->d_name.name, |
1808 | buflen -= namelen + 1; | 1816 | dentry->d_name.len) != 0) || |
1809 | if (buflen < 0) | 1817 | (prepend(&end, &buflen, "/", 1) != 0)) |
1810 | goto Elong; | 1818 | goto Elong; |
1811 | end -= namelen; | ||
1812 | memcpy(end, dentry->d_name.name, namelen); | ||
1813 | *--end = '/'; | ||
1814 | retval = end; | 1819 | retval = end; |
1815 | dentry = parent; | 1820 | dentry = parent; |
1816 | } | 1821 | } |
@@ -1818,12 +1823,12 @@ static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, | |||
1818 | return retval; | 1823 | return retval; |
1819 | 1824 | ||
1820 | global_root: | 1825 | global_root: |
1821 | namelen = dentry->d_name.len; | 1826 | retval += 1; /* hit the slash */ |
1822 | buflen -= namelen; | 1827 | if (prepend(&retval, &buflen, dentry->d_name.name, |
1823 | if (buflen < 0) | 1828 | dentry->d_name.len) != 0) |
1824 | goto Elong; | 1829 | goto Elong; |
1825 | retval -= namelen-1; /* hit the slash */ | 1830 | root->mnt = vfsmnt; |
1826 | memcpy(retval, dentry->d_name.name, namelen); | 1831 | root->dentry = dentry; |
1827 | return retval; | 1832 | return retval; |
1828 | Elong: | 1833 | Elong: |
1829 | return ERR_PTR(-ENAMETOOLONG); | 1834 | return ERR_PTR(-ENAMETOOLONG); |
@@ -1846,6 +1851,7 @@ char *d_path(struct path *path, char *buf, int buflen) | |||
1846 | { | 1851 | { |
1847 | char *res; | 1852 | char *res; |
1848 | struct path root; | 1853 | struct path root; |
1854 | struct path tmp; | ||
1849 | 1855 | ||
1850 | /* | 1856 | /* |
1851 | * We have various synthetic filesystems that never get mounted. On | 1857 | * We have various synthetic filesystems that never get mounted. On |
@@ -1859,10 +1865,11 @@ char *d_path(struct path *path, char *buf, int buflen) | |||
1859 | 1865 | ||
1860 | read_lock(¤t->fs->lock); | 1866 | read_lock(¤t->fs->lock); |
1861 | root = current->fs->root; | 1867 | root = current->fs->root; |
1862 | path_get(¤t->fs->root); | 1868 | path_get(&root); |
1863 | read_unlock(¤t->fs->lock); | 1869 | read_unlock(¤t->fs->lock); |
1864 | spin_lock(&dcache_lock); | 1870 | spin_lock(&dcache_lock); |
1865 | res = __d_path(path->dentry, path->mnt, &root, buf, buflen); | 1871 | tmp = root; |
1872 | res = __d_path(path, &tmp, buf, buflen); | ||
1866 | spin_unlock(&dcache_lock); | 1873 | spin_unlock(&dcache_lock); |
1867 | path_put(&root); | 1874 | path_put(&root); |
1868 | return res; | 1875 | return res; |
@@ -1890,6 +1897,48 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen, | |||
1890 | } | 1897 | } |
1891 | 1898 | ||
1892 | /* | 1899 | /* |
1900 | * Write full pathname from the root of the filesystem into the buffer. | ||
1901 | */ | ||
1902 | char *dentry_path(struct dentry *dentry, char *buf, int buflen) | ||
1903 | { | ||
1904 | char *end = buf + buflen; | ||
1905 | char *retval; | ||
1906 | |||
1907 | spin_lock(&dcache_lock); | ||
1908 | prepend(&end, &buflen, "\0", 1); | ||
1909 | if (!IS_ROOT(dentry) && d_unhashed(dentry) && | ||
1910 | (prepend(&end, &buflen, "//deleted", 9) != 0)) | ||
1911 | goto Elong; | ||
1912 | if (buflen < 1) | ||
1913 | goto Elong; | ||
1914 | /* Get '/' right */ | ||
1915 | retval = end-1; | ||
1916 | *retval = '/'; | ||
1917 | |||
1918 | for (;;) { | ||
1919 | struct dentry *parent; | ||
1920 | if (IS_ROOT(dentry)) | ||
1921 | break; | ||
1922 | |||
1923 | parent = dentry->d_parent; | ||
1924 | prefetch(parent); | ||
1925 | |||
1926 | if ((prepend(&end, &buflen, dentry->d_name.name, | ||
1927 | dentry->d_name.len) != 0) || | ||
1928 | (prepend(&end, &buflen, "/", 1) != 0)) | ||
1929 | goto Elong; | ||
1930 | |||
1931 | retval = end; | ||
1932 | dentry = parent; | ||
1933 | } | ||
1934 | spin_unlock(&dcache_lock); | ||
1935 | return retval; | ||
1936 | Elong: | ||
1937 | spin_unlock(&dcache_lock); | ||
1938 | return ERR_PTR(-ENAMETOOLONG); | ||
1939 | } | ||
1940 | |||
1941 | /* | ||
1893 | * NOTE! The user-level library version returns a | 1942 | * NOTE! The user-level library version returns a |
1894 | * character pointer. The kernel system call just | 1943 | * character pointer. The kernel system call just |
1895 | * returns the length of the buffer filled (which | 1944 | * returns the length of the buffer filled (which |
@@ -1918,9 +1967,9 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) | |||
1918 | 1967 | ||
1919 | read_lock(¤t->fs->lock); | 1968 | read_lock(¤t->fs->lock); |
1920 | pwd = current->fs->pwd; | 1969 | pwd = current->fs->pwd; |
1921 | path_get(¤t->fs->pwd); | 1970 | path_get(&pwd); |
1922 | root = current->fs->root; | 1971 | root = current->fs->root; |
1923 | path_get(¤t->fs->root); | 1972 | path_get(&root); |
1924 | read_unlock(¤t->fs->lock); | 1973 | read_unlock(¤t->fs->lock); |
1925 | 1974 | ||
1926 | error = -ENOENT; | 1975 | error = -ENOENT; |
@@ -1928,9 +1977,10 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) | |||
1928 | spin_lock(&dcache_lock); | 1977 | spin_lock(&dcache_lock); |
1929 | if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) { | 1978 | if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) { |
1930 | unsigned long len; | 1979 | unsigned long len; |
1980 | struct path tmp = root; | ||
1931 | char * cwd; | 1981 | char * cwd; |
1932 | 1982 | ||
1933 | cwd = __d_path(pwd.dentry, pwd.mnt, &root, page, PAGE_SIZE); | 1983 | cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE); |
1934 | spin_unlock(&dcache_lock); | 1984 | spin_unlock(&dcache_lock); |
1935 | 1985 | ||
1936 | error = PTR_ERR(cwd); | 1986 | error = PTR_ERR(cwd); |
diff --git a/fs/dlm/Makefile b/fs/dlm/Makefile index d248e60951ba..ca1c9124c8ce 100644 --- a/fs/dlm/Makefile +++ b/fs/dlm/Makefile | |||
@@ -10,6 +10,7 @@ dlm-y := ast.o \ | |||
10 | midcomms.o \ | 10 | midcomms.o \ |
11 | netlink.o \ | 11 | netlink.o \ |
12 | lowcomms.o \ | 12 | lowcomms.o \ |
13 | plock.o \ | ||
13 | rcom.o \ | 14 | rcom.o \ |
14 | recover.o \ | 15 | recover.o \ |
15 | recoverd.o \ | 16 | recoverd.o \ |
diff --git a/fs/dlm/config.c b/fs/dlm/config.c index c3ad1dff3b25..eac23bd288b2 100644 --- a/fs/dlm/config.c +++ b/fs/dlm/config.c | |||
@@ -114,7 +114,7 @@ struct cluster_attribute { | |||
114 | }; | 114 | }; |
115 | 115 | ||
116 | static ssize_t cluster_set(struct cluster *cl, unsigned int *cl_field, | 116 | static ssize_t cluster_set(struct cluster *cl, unsigned int *cl_field, |
117 | unsigned int *info_field, int check_zero, | 117 | int *info_field, int check_zero, |
118 | const char *buf, size_t len) | 118 | const char *buf, size_t len) |
119 | { | 119 | { |
120 | unsigned int x; | 120 | unsigned int x; |
@@ -284,6 +284,7 @@ struct node { | |||
284 | struct list_head list; /* space->members */ | 284 | struct list_head list; /* space->members */ |
285 | int nodeid; | 285 | int nodeid; |
286 | int weight; | 286 | int weight; |
287 | int new; | ||
287 | }; | 288 | }; |
288 | 289 | ||
289 | static struct configfs_group_operations clusters_ops = { | 290 | static struct configfs_group_operations clusters_ops = { |
@@ -565,6 +566,7 @@ static struct config_item *make_node(struct config_group *g, const char *name) | |||
565 | config_item_init_type_name(&nd->item, name, &node_type); | 566 | config_item_init_type_name(&nd->item, name, &node_type); |
566 | nd->nodeid = -1; | 567 | nd->nodeid = -1; |
567 | nd->weight = 1; /* default weight of 1 if none is set */ | 568 | nd->weight = 1; /* default weight of 1 if none is set */ |
569 | nd->new = 1; /* set to 0 once it's been read by dlm_nodeid_list() */ | ||
568 | 570 | ||
569 | mutex_lock(&sp->members_lock); | 571 | mutex_lock(&sp->members_lock); |
570 | list_add(&nd->list, &sp->members); | 572 | list_add(&nd->list, &sp->members); |
@@ -805,12 +807,13 @@ static void put_comm(struct comm *cm) | |||
805 | } | 807 | } |
806 | 808 | ||
807 | /* caller must free mem */ | 809 | /* caller must free mem */ |
808 | int dlm_nodeid_list(char *lsname, int **ids_out) | 810 | int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out, |
811 | int **new_out, int *new_count_out) | ||
809 | { | 812 | { |
810 | struct space *sp; | 813 | struct space *sp; |
811 | struct node *nd; | 814 | struct node *nd; |
812 | int i = 0, rv = 0; | 815 | int i = 0, rv = 0, ids_count = 0, new_count = 0; |
813 | int *ids; | 816 | int *ids, *new; |
814 | 817 | ||
815 | sp = get_space(lsname); | 818 | sp = get_space(lsname); |
816 | if (!sp) | 819 | if (!sp) |
@@ -818,23 +821,50 @@ int dlm_nodeid_list(char *lsname, int **ids_out) | |||
818 | 821 | ||
819 | mutex_lock(&sp->members_lock); | 822 | mutex_lock(&sp->members_lock); |
820 | if (!sp->members_count) { | 823 | if (!sp->members_count) { |
821 | rv = 0; | 824 | rv = -EINVAL; |
825 | printk(KERN_ERR "dlm: zero members_count\n"); | ||
822 | goto out; | 826 | goto out; |
823 | } | 827 | } |
824 | 828 | ||
825 | ids = kcalloc(sp->members_count, sizeof(int), GFP_KERNEL); | 829 | ids_count = sp->members_count; |
830 | |||
831 | ids = kcalloc(ids_count, sizeof(int), GFP_KERNEL); | ||
826 | if (!ids) { | 832 | if (!ids) { |
827 | rv = -ENOMEM; | 833 | rv = -ENOMEM; |
828 | goto out; | 834 | goto out; |
829 | } | 835 | } |
830 | 836 | ||
831 | rv = sp->members_count; | 837 | list_for_each_entry(nd, &sp->members, list) { |
832 | list_for_each_entry(nd, &sp->members, list) | ||
833 | ids[i++] = nd->nodeid; | 838 | ids[i++] = nd->nodeid; |
839 | if (nd->new) | ||
840 | new_count++; | ||
841 | } | ||
842 | |||
843 | if (ids_count != i) | ||
844 | printk(KERN_ERR "dlm: bad nodeid count %d %d\n", ids_count, i); | ||
845 | |||
846 | if (!new_count) | ||
847 | goto out_ids; | ||
848 | |||
849 | new = kcalloc(new_count, sizeof(int), GFP_KERNEL); | ||
850 | if (!new) { | ||
851 | kfree(ids); | ||
852 | rv = -ENOMEM; | ||
853 | goto out; | ||
854 | } | ||
834 | 855 | ||
835 | if (rv != i) | 856 | i = 0; |
836 | printk("bad nodeid count %d %d\n", rv, i); | 857 | list_for_each_entry(nd, &sp->members, list) { |
858 | if (nd->new) { | ||
859 | new[i++] = nd->nodeid; | ||
860 | nd->new = 0; | ||
861 | } | ||
862 | } | ||
863 | *new_count_out = new_count; | ||
864 | *new_out = new; | ||
837 | 865 | ||
866 | out_ids: | ||
867 | *ids_count_out = ids_count; | ||
838 | *ids_out = ids; | 868 | *ids_out = ids; |
839 | out: | 869 | out: |
840 | mutex_unlock(&sp->members_lock); | 870 | mutex_unlock(&sp->members_lock); |
diff --git a/fs/dlm/config.h b/fs/dlm/config.h index a3170fe22090..4f1d6fce58c5 100644 --- a/fs/dlm/config.h +++ b/fs/dlm/config.h | |||
@@ -35,7 +35,8 @@ extern struct dlm_config_info dlm_config; | |||
35 | int dlm_config_init(void); | 35 | int dlm_config_init(void); |
36 | void dlm_config_exit(void); | 36 | void dlm_config_exit(void); |
37 | int dlm_node_weight(char *lsname, int nodeid); | 37 | int dlm_node_weight(char *lsname, int nodeid); |
38 | int dlm_nodeid_list(char *lsname, int **ids_out); | 38 | int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out, |
39 | int **new_out, int *new_count_out); | ||
39 | int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr); | 40 | int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr); |
40 | int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid); | 41 | int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid); |
41 | int dlm_our_nodeid(void); | 42 | int dlm_our_nodeid(void); |
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h index 7a8824f475f2..5a7ac33b629c 100644 --- a/fs/dlm/dlm_internal.h +++ b/fs/dlm/dlm_internal.h | |||
@@ -42,8 +42,6 @@ | |||
42 | #include <linux/dlm.h> | 42 | #include <linux/dlm.h> |
43 | #include "config.h" | 43 | #include "config.h" |
44 | 44 | ||
45 | #define DLM_LOCKSPACE_LEN 64 | ||
46 | |||
47 | /* Size of the temp buffer midcomms allocates on the stack. | 45 | /* Size of the temp buffer midcomms allocates on the stack. |
48 | We try to make this large enough so most messages fit. | 46 | We try to make this large enough so most messages fit. |
49 | FIXME: should sctp make this unnecessary? */ | 47 | FIXME: should sctp make this unnecessary? */ |
@@ -132,8 +130,10 @@ struct dlm_member { | |||
132 | 130 | ||
133 | struct dlm_recover { | 131 | struct dlm_recover { |
134 | struct list_head list; | 132 | struct list_head list; |
135 | int *nodeids; | 133 | int *nodeids; /* nodeids of all members */ |
136 | int node_count; | 134 | int node_count; |
135 | int *new; /* nodeids of new members */ | ||
136 | int new_count; | ||
137 | uint64_t seq; | 137 | uint64_t seq; |
138 | }; | 138 | }; |
139 | 139 | ||
@@ -579,6 +579,8 @@ static inline int dlm_no_directory(struct dlm_ls *ls) | |||
579 | int dlm_netlink_init(void); | 579 | int dlm_netlink_init(void); |
580 | void dlm_netlink_exit(void); | 580 | void dlm_netlink_exit(void); |
581 | void dlm_timeout_warn(struct dlm_lkb *lkb); | 581 | void dlm_timeout_warn(struct dlm_lkb *lkb); |
582 | int dlm_plock_init(void); | ||
583 | void dlm_plock_exit(void); | ||
582 | 584 | ||
583 | #ifdef CONFIG_DLM_DEBUG | 585 | #ifdef CONFIG_DLM_DEBUG |
584 | int dlm_register_debugfs(void); | 586 | int dlm_register_debugfs(void); |
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 8f250ac8b928..2d3d1027ce2b 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c | |||
@@ -165,7 +165,7 @@ void dlm_print_lkb(struct dlm_lkb *lkb) | |||
165 | lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_ast_type); | 165 | lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_ast_type); |
166 | } | 166 | } |
167 | 167 | ||
168 | void dlm_print_rsb(struct dlm_rsb *r) | 168 | static void dlm_print_rsb(struct dlm_rsb *r) |
169 | { | 169 | { |
170 | printk(KERN_ERR "rsb: nodeid %d flags %lx first %x rlc %d name %s\n", | 170 | printk(KERN_ERR "rsb: nodeid %d flags %lx first %x rlc %d name %s\n", |
171 | r->res_nodeid, r->res_flags, r->res_first_lkid, | 171 | r->res_nodeid, r->res_flags, r->res_first_lkid, |
@@ -1956,8 +1956,7 @@ static void confirm_master(struct dlm_rsb *r, int error) | |||
1956 | list_del_init(&lkb->lkb_rsb_lookup); | 1956 | list_del_init(&lkb->lkb_rsb_lookup); |
1957 | r->res_first_lkid = lkb->lkb_id; | 1957 | r->res_first_lkid = lkb->lkb_id; |
1958 | _request_lock(r, lkb); | 1958 | _request_lock(r, lkb); |
1959 | } else | 1959 | } |
1960 | r->res_nodeid = -1; | ||
1961 | break; | 1960 | break; |
1962 | 1961 | ||
1963 | default: | 1962 | default: |
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h index 05d9c82e646b..88e93c80cc22 100644 --- a/fs/dlm/lock.h +++ b/fs/dlm/lock.h | |||
@@ -13,7 +13,6 @@ | |||
13 | #ifndef __LOCK_DOT_H__ | 13 | #ifndef __LOCK_DOT_H__ |
14 | #define __LOCK_DOT_H__ | 14 | #define __LOCK_DOT_H__ |
15 | 15 | ||
16 | void dlm_print_rsb(struct dlm_rsb *r); | ||
17 | void dlm_dump_rsb(struct dlm_rsb *r); | 16 | void dlm_dump_rsb(struct dlm_rsb *r); |
18 | void dlm_print_lkb(struct dlm_lkb *lkb); | 17 | void dlm_print_lkb(struct dlm_lkb *lkb); |
19 | void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms); | 18 | void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms); |
diff --git a/fs/dlm/main.c b/fs/dlm/main.c index 58487fb95a4c..b80e0aa3cfa5 100644 --- a/fs/dlm/main.c +++ b/fs/dlm/main.c | |||
@@ -46,10 +46,16 @@ static int __init init_dlm(void) | |||
46 | if (error) | 46 | if (error) |
47 | goto out_user; | 47 | goto out_user; |
48 | 48 | ||
49 | error = dlm_plock_init(); | ||
50 | if (error) | ||
51 | goto out_netlink; | ||
52 | |||
49 | printk("DLM (built %s %s) installed\n", __DATE__, __TIME__); | 53 | printk("DLM (built %s %s) installed\n", __DATE__, __TIME__); |
50 | 54 | ||
51 | return 0; | 55 | return 0; |
52 | 56 | ||
57 | out_netlink: | ||
58 | dlm_netlink_exit(); | ||
53 | out_user: | 59 | out_user: |
54 | dlm_user_exit(); | 60 | dlm_user_exit(); |
55 | out_debug: | 61 | out_debug: |
@@ -66,6 +72,7 @@ static int __init init_dlm(void) | |||
66 | 72 | ||
67 | static void __exit exit_dlm(void) | 73 | static void __exit exit_dlm(void) |
68 | { | 74 | { |
75 | dlm_plock_exit(); | ||
69 | dlm_netlink_exit(); | 76 | dlm_netlink_exit(); |
70 | dlm_user_exit(); | 77 | dlm_user_exit(); |
71 | dlm_config_exit(); | 78 | dlm_config_exit(); |
diff --git a/fs/dlm/member.c b/fs/dlm/member.c index fa17f5a27883..26133f05ae3a 100644 --- a/fs/dlm/member.c +++ b/fs/dlm/member.c | |||
@@ -210,6 +210,23 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out) | |||
210 | } | 210 | } |
211 | } | 211 | } |
212 | 212 | ||
213 | /* Add an entry to ls_nodes_gone for members that were removed and | ||
214 | then added again, so that previous state for these nodes will be | ||
215 | cleared during recovery. */ | ||
216 | |||
217 | for (i = 0; i < rv->new_count; i++) { | ||
218 | if (!dlm_is_member(ls, rv->new[i])) | ||
219 | continue; | ||
220 | log_debug(ls, "new nodeid %d is a re-added member", rv->new[i]); | ||
221 | |||
222 | memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL); | ||
223 | if (!memb) | ||
224 | return -ENOMEM; | ||
225 | memb->nodeid = rv->new[i]; | ||
226 | list_add_tail(&memb->list, &ls->ls_nodes_gone); | ||
227 | neg++; | ||
228 | } | ||
229 | |||
213 | /* add new members to ls_nodes */ | 230 | /* add new members to ls_nodes */ |
214 | 231 | ||
215 | for (i = 0; i < rv->node_count; i++) { | 232 | for (i = 0; i < rv->node_count; i++) { |
@@ -314,15 +331,16 @@ int dlm_ls_stop(struct dlm_ls *ls) | |||
314 | int dlm_ls_start(struct dlm_ls *ls) | 331 | int dlm_ls_start(struct dlm_ls *ls) |
315 | { | 332 | { |
316 | struct dlm_recover *rv = NULL, *rv_old; | 333 | struct dlm_recover *rv = NULL, *rv_old; |
317 | int *ids = NULL; | 334 | int *ids = NULL, *new = NULL; |
318 | int error, count; | 335 | int error, ids_count = 0, new_count = 0; |
319 | 336 | ||
320 | rv = kzalloc(sizeof(struct dlm_recover), GFP_KERNEL); | 337 | rv = kzalloc(sizeof(struct dlm_recover), GFP_KERNEL); |
321 | if (!rv) | 338 | if (!rv) |
322 | return -ENOMEM; | 339 | return -ENOMEM; |
323 | 340 | ||
324 | error = count = dlm_nodeid_list(ls->ls_name, &ids); | 341 | error = dlm_nodeid_list(ls->ls_name, &ids, &ids_count, |
325 | if (error <= 0) | 342 | &new, &new_count); |
343 | if (error < 0) | ||
326 | goto fail; | 344 | goto fail; |
327 | 345 | ||
328 | spin_lock(&ls->ls_recover_lock); | 346 | spin_lock(&ls->ls_recover_lock); |
@@ -337,14 +355,19 @@ int dlm_ls_start(struct dlm_ls *ls) | |||
337 | } | 355 | } |
338 | 356 | ||
339 | rv->nodeids = ids; | 357 | rv->nodeids = ids; |
340 | rv->node_count = count; | 358 | rv->node_count = ids_count; |
359 | rv->new = new; | ||
360 | rv->new_count = new_count; | ||
341 | rv->seq = ++ls->ls_recover_seq; | 361 | rv->seq = ++ls->ls_recover_seq; |
342 | rv_old = ls->ls_recover_args; | 362 | rv_old = ls->ls_recover_args; |
343 | ls->ls_recover_args = rv; | 363 | ls->ls_recover_args = rv; |
344 | spin_unlock(&ls->ls_recover_lock); | 364 | spin_unlock(&ls->ls_recover_lock); |
345 | 365 | ||
346 | if (rv_old) { | 366 | if (rv_old) { |
367 | log_error(ls, "unused recovery %llx %d", | ||
368 | (unsigned long long)rv_old->seq, rv_old->node_count); | ||
347 | kfree(rv_old->nodeids); | 369 | kfree(rv_old->nodeids); |
370 | kfree(rv_old->new); | ||
348 | kfree(rv_old); | 371 | kfree(rv_old); |
349 | } | 372 | } |
350 | 373 | ||
@@ -354,6 +377,7 @@ int dlm_ls_start(struct dlm_ls *ls) | |||
354 | fail: | 377 | fail: |
355 | kfree(rv); | 378 | kfree(rv); |
356 | kfree(ids); | 379 | kfree(ids); |
380 | kfree(new); | ||
357 | return error; | 381 | return error; |
358 | } | 382 | } |
359 | 383 | ||
diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/dlm/plock.c index 2ebd374b3143..d6d6e370f89c 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/dlm/plock.c | |||
@@ -1,17 +1,19 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2005 Red Hat, Inc. All rights reserved. | 2 | * Copyright (C) 2005-2008 Red Hat, Inc. All rights reserved. |
3 | * | 3 | * |
4 | * This copyrighted material is made available to anyone wishing to use, | 4 | * This copyrighted material is made available to anyone wishing to use, |
5 | * modify, copy, or redistribute it subject to the terms and conditions | 5 | * modify, copy, or redistribute it subject to the terms and conditions |
6 | * of the GNU General Public License version 2. | 6 | * of the GNU General Public License version 2. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/fs.h> | ||
9 | #include <linux/miscdevice.h> | 10 | #include <linux/miscdevice.h> |
10 | #include <linux/lock_dlm_plock.h> | ||
11 | #include <linux/poll.h> | 11 | #include <linux/poll.h> |
12 | #include <linux/dlm.h> | ||
13 | #include <linux/dlm_plock.h> | ||
12 | 14 | ||
13 | #include "lock_dlm.h" | 15 | #include "dlm_internal.h" |
14 | 16 | #include "lockspace.h" | |
15 | 17 | ||
16 | static spinlock_t ops_lock; | 18 | static spinlock_t ops_lock; |
17 | static struct list_head send_list; | 19 | static struct list_head send_list; |
@@ -22,7 +24,7 @@ static wait_queue_head_t recv_wq; | |||
22 | struct plock_op { | 24 | struct plock_op { |
23 | struct list_head list; | 25 | struct list_head list; |
24 | int done; | 26 | int done; |
25 | struct gdlm_plock_info info; | 27 | struct dlm_plock_info info; |
26 | }; | 28 | }; |
27 | 29 | ||
28 | struct plock_xop { | 30 | struct plock_xop { |
@@ -34,22 +36,22 @@ struct plock_xop { | |||
34 | }; | 36 | }; |
35 | 37 | ||
36 | 38 | ||
37 | static inline void set_version(struct gdlm_plock_info *info) | 39 | static inline void set_version(struct dlm_plock_info *info) |
38 | { | 40 | { |
39 | info->version[0] = GDLM_PLOCK_VERSION_MAJOR; | 41 | info->version[0] = DLM_PLOCK_VERSION_MAJOR; |
40 | info->version[1] = GDLM_PLOCK_VERSION_MINOR; | 42 | info->version[1] = DLM_PLOCK_VERSION_MINOR; |
41 | info->version[2] = GDLM_PLOCK_VERSION_PATCH; | 43 | info->version[2] = DLM_PLOCK_VERSION_PATCH; |
42 | } | 44 | } |
43 | 45 | ||
44 | static int check_version(struct gdlm_plock_info *info) | 46 | static int check_version(struct dlm_plock_info *info) |
45 | { | 47 | { |
46 | if ((GDLM_PLOCK_VERSION_MAJOR != info->version[0]) || | 48 | if ((DLM_PLOCK_VERSION_MAJOR != info->version[0]) || |
47 | (GDLM_PLOCK_VERSION_MINOR < info->version[1])) { | 49 | (DLM_PLOCK_VERSION_MINOR < info->version[1])) { |
48 | log_error("plock device version mismatch: " | 50 | log_print("plock device version mismatch: " |
49 | "kernel (%u.%u.%u), user (%u.%u.%u)", | 51 | "kernel (%u.%u.%u), user (%u.%u.%u)", |
50 | GDLM_PLOCK_VERSION_MAJOR, | 52 | DLM_PLOCK_VERSION_MAJOR, |
51 | GDLM_PLOCK_VERSION_MINOR, | 53 | DLM_PLOCK_VERSION_MINOR, |
52 | GDLM_PLOCK_VERSION_PATCH, | 54 | DLM_PLOCK_VERSION_PATCH, |
53 | info->version[0], | 55 | info->version[0], |
54 | info->version[1], | 56 | info->version[1], |
55 | info->version[2]); | 57 | info->version[2]); |
@@ -68,25 +70,31 @@ static void send_op(struct plock_op *op) | |||
68 | wake_up(&send_wq); | 70 | wake_up(&send_wq); |
69 | } | 71 | } |
70 | 72 | ||
71 | int gdlm_plock(void *lockspace, struct lm_lockname *name, | 73 | int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file, |
72 | struct file *file, int cmd, struct file_lock *fl) | 74 | int cmd, struct file_lock *fl) |
73 | { | 75 | { |
74 | struct gdlm_ls *ls = lockspace; | 76 | struct dlm_ls *ls; |
75 | struct plock_op *op; | 77 | struct plock_op *op; |
76 | struct plock_xop *xop; | 78 | struct plock_xop *xop; |
77 | int rv; | 79 | int rv; |
78 | 80 | ||
81 | ls = dlm_find_lockspace_local(lockspace); | ||
82 | if (!ls) | ||
83 | return -EINVAL; | ||
84 | |||
79 | xop = kzalloc(sizeof(*xop), GFP_KERNEL); | 85 | xop = kzalloc(sizeof(*xop), GFP_KERNEL); |
80 | if (!xop) | 86 | if (!xop) { |
81 | return -ENOMEM; | 87 | rv = -ENOMEM; |
88 | goto out; | ||
89 | } | ||
82 | 90 | ||
83 | op = &xop->xop; | 91 | op = &xop->xop; |
84 | op->info.optype = GDLM_PLOCK_OP_LOCK; | 92 | op->info.optype = DLM_PLOCK_OP_LOCK; |
85 | op->info.pid = fl->fl_pid; | 93 | op->info.pid = fl->fl_pid; |
86 | op->info.ex = (fl->fl_type == F_WRLCK); | 94 | op->info.ex = (fl->fl_type == F_WRLCK); |
87 | op->info.wait = IS_SETLKW(cmd); | 95 | op->info.wait = IS_SETLKW(cmd); |
88 | op->info.fsid = ls->id; | 96 | op->info.fsid = ls->ls_global_id; |
89 | op->info.number = name->ln_number; | 97 | op->info.number = number; |
90 | op->info.start = fl->fl_start; | 98 | op->info.start = fl->fl_start; |
91 | op->info.end = fl->fl_end; | 99 | op->info.end = fl->fl_end; |
92 | if (fl->fl_lmops && fl->fl_lmops->fl_grant) { | 100 | if (fl->fl_lmops && fl->fl_lmops->fl_grant) { |
@@ -107,12 +115,15 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name, | |||
107 | 115 | ||
108 | if (xop->callback == NULL) | 116 | if (xop->callback == NULL) |
109 | wait_event(recv_wq, (op->done != 0)); | 117 | wait_event(recv_wq, (op->done != 0)); |
110 | else | 118 | else { |
111 | return -EINPROGRESS; | 119 | rv = -EINPROGRESS; |
120 | goto out; | ||
121 | } | ||
112 | 122 | ||
113 | spin_lock(&ops_lock); | 123 | spin_lock(&ops_lock); |
114 | if (!list_empty(&op->list)) { | 124 | if (!list_empty(&op->list)) { |
115 | printk(KERN_INFO "plock op on list\n"); | 125 | log_error(ls, "dlm_posix_lock: op on list %llx", |
126 | (unsigned long long)number); | ||
116 | list_del(&op->list); | 127 | list_del(&op->list); |
117 | } | 128 | } |
118 | spin_unlock(&ops_lock); | 129 | spin_unlock(&ops_lock); |
@@ -121,17 +132,19 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name, | |||
121 | 132 | ||
122 | if (!rv) { | 133 | if (!rv) { |
123 | if (posix_lock_file_wait(file, fl) < 0) | 134 | if (posix_lock_file_wait(file, fl) < 0) |
124 | log_error("gdlm_plock: vfs lock error %x,%llx", | 135 | log_error(ls, "dlm_posix_lock: vfs lock error %llx", |
125 | name->ln_type, | 136 | (unsigned long long)number); |
126 | (unsigned long long)name->ln_number); | ||
127 | } | 137 | } |
128 | 138 | ||
129 | kfree(xop); | 139 | kfree(xop); |
140 | out: | ||
141 | dlm_put_lockspace(ls); | ||
130 | return rv; | 142 | return rv; |
131 | } | 143 | } |
144 | EXPORT_SYMBOL_GPL(dlm_posix_lock); | ||
132 | 145 | ||
133 | /* Returns failure iff a succesful lock operation should be canceled */ | 146 | /* Returns failure iff a succesful lock operation should be canceled */ |
134 | static int gdlm_plock_callback(struct plock_op *op) | 147 | static int dlm_plock_callback(struct plock_op *op) |
135 | { | 148 | { |
136 | struct file *file; | 149 | struct file *file; |
137 | struct file_lock *fl; | 150 | struct file_lock *fl; |
@@ -142,7 +155,8 @@ static int gdlm_plock_callback(struct plock_op *op) | |||
142 | 155 | ||
143 | spin_lock(&ops_lock); | 156 | spin_lock(&ops_lock); |
144 | if (!list_empty(&op->list)) { | 157 | if (!list_empty(&op->list)) { |
145 | printk(KERN_INFO "plock op on list\n"); | 158 | log_print("dlm_plock_callback: op on list %llx", |
159 | (unsigned long long)op->info.number); | ||
146 | list_del(&op->list); | 160 | list_del(&op->list); |
147 | } | 161 | } |
148 | spin_unlock(&ops_lock); | 162 | spin_unlock(&ops_lock); |
@@ -165,19 +179,19 @@ static int gdlm_plock_callback(struct plock_op *op) | |||
165 | * This can only happen in the case of kmalloc() failure. | 179 | * This can only happen in the case of kmalloc() failure. |
166 | * The filesystem's own lock is the authoritative lock, | 180 | * The filesystem's own lock is the authoritative lock, |
167 | * so a failure to get the lock locally is not a disaster. | 181 | * so a failure to get the lock locally is not a disaster. |
168 | * As long as GFS cannot reliably cancel locks (especially | 182 | * As long as the fs cannot reliably cancel locks (especially |
169 | * in a low-memory situation), we're better off ignoring | 183 | * in a low-memory situation), we're better off ignoring |
170 | * this failure than trying to recover. | 184 | * this failure than trying to recover. |
171 | */ | 185 | */ |
172 | log_error("gdlm_plock: vfs lock error file %p fl %p", | 186 | log_print("dlm_plock_callback: vfs lock error %llx file %p fl %p", |
173 | file, fl); | 187 | (unsigned long long)op->info.number, file, fl); |
174 | } | 188 | } |
175 | 189 | ||
176 | rv = notify(flc, NULL, 0); | 190 | rv = notify(flc, NULL, 0); |
177 | if (rv) { | 191 | if (rv) { |
178 | /* XXX: We need to cancel the fs lock here: */ | 192 | /* XXX: We need to cancel the fs lock here: */ |
179 | printk("gfs2 lock granted after lock request failed;" | 193 | log_print("dlm_plock_callback: lock granted after lock request " |
180 | " dangling lock!\n"); | 194 | "failed; dangling lock!\n"); |
181 | goto out; | 195 | goto out; |
182 | } | 196 | } |
183 | 197 | ||
@@ -186,25 +200,31 @@ out: | |||
186 | return rv; | 200 | return rv; |
187 | } | 201 | } |
188 | 202 | ||
189 | int gdlm_punlock(void *lockspace, struct lm_lockname *name, | 203 | int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file, |
190 | struct file *file, struct file_lock *fl) | 204 | struct file_lock *fl) |
191 | { | 205 | { |
192 | struct gdlm_ls *ls = lockspace; | 206 | struct dlm_ls *ls; |
193 | struct plock_op *op; | 207 | struct plock_op *op; |
194 | int rv; | 208 | int rv; |
195 | 209 | ||
210 | ls = dlm_find_lockspace_local(lockspace); | ||
211 | if (!ls) | ||
212 | return -EINVAL; | ||
213 | |||
196 | op = kzalloc(sizeof(*op), GFP_KERNEL); | 214 | op = kzalloc(sizeof(*op), GFP_KERNEL); |
197 | if (!op) | 215 | if (!op) { |
198 | return -ENOMEM; | 216 | rv = -ENOMEM; |
217 | goto out; | ||
218 | } | ||
199 | 219 | ||
200 | if (posix_lock_file_wait(file, fl) < 0) | 220 | if (posix_lock_file_wait(file, fl) < 0) |
201 | log_error("gdlm_punlock: vfs unlock error %x,%llx", | 221 | log_error(ls, "dlm_posix_unlock: vfs unlock error %llx", |
202 | name->ln_type, (unsigned long long)name->ln_number); | 222 | (unsigned long long)number); |
203 | 223 | ||
204 | op->info.optype = GDLM_PLOCK_OP_UNLOCK; | 224 | op->info.optype = DLM_PLOCK_OP_UNLOCK; |
205 | op->info.pid = fl->fl_pid; | 225 | op->info.pid = fl->fl_pid; |
206 | op->info.fsid = ls->id; | 226 | op->info.fsid = ls->ls_global_id; |
207 | op->info.number = name->ln_number; | 227 | op->info.number = number; |
208 | op->info.start = fl->fl_start; | 228 | op->info.start = fl->fl_start; |
209 | op->info.end = fl->fl_end; | 229 | op->info.end = fl->fl_end; |
210 | if (fl->fl_lmops && fl->fl_lmops->fl_grant) | 230 | if (fl->fl_lmops && fl->fl_lmops->fl_grant) |
@@ -217,7 +237,8 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name, | |||
217 | 237 | ||
218 | spin_lock(&ops_lock); | 238 | spin_lock(&ops_lock); |
219 | if (!list_empty(&op->list)) { | 239 | if (!list_empty(&op->list)) { |
220 | printk(KERN_INFO "punlock op on list\n"); | 240 | log_error(ls, "dlm_posix_unlock: op on list %llx", |
241 | (unsigned long long)number); | ||
221 | list_del(&op->list); | 242 | list_del(&op->list); |
222 | } | 243 | } |
223 | spin_unlock(&ops_lock); | 244 | spin_unlock(&ops_lock); |
@@ -228,25 +249,34 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name, | |||
228 | rv = 0; | 249 | rv = 0; |
229 | 250 | ||
230 | kfree(op); | 251 | kfree(op); |
252 | out: | ||
253 | dlm_put_lockspace(ls); | ||
231 | return rv; | 254 | return rv; |
232 | } | 255 | } |
256 | EXPORT_SYMBOL_GPL(dlm_posix_unlock); | ||
233 | 257 | ||
234 | int gdlm_plock_get(void *lockspace, struct lm_lockname *name, | 258 | int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file, |
235 | struct file *file, struct file_lock *fl) | 259 | struct file_lock *fl) |
236 | { | 260 | { |
237 | struct gdlm_ls *ls = lockspace; | 261 | struct dlm_ls *ls; |
238 | struct plock_op *op; | 262 | struct plock_op *op; |
239 | int rv; | 263 | int rv; |
240 | 264 | ||
265 | ls = dlm_find_lockspace_local(lockspace); | ||
266 | if (!ls) | ||
267 | return -EINVAL; | ||
268 | |||
241 | op = kzalloc(sizeof(*op), GFP_KERNEL); | 269 | op = kzalloc(sizeof(*op), GFP_KERNEL); |
242 | if (!op) | 270 | if (!op) { |
243 | return -ENOMEM; | 271 | rv = -ENOMEM; |
272 | goto out; | ||
273 | } | ||
244 | 274 | ||
245 | op->info.optype = GDLM_PLOCK_OP_GET; | 275 | op->info.optype = DLM_PLOCK_OP_GET; |
246 | op->info.pid = fl->fl_pid; | 276 | op->info.pid = fl->fl_pid; |
247 | op->info.ex = (fl->fl_type == F_WRLCK); | 277 | op->info.ex = (fl->fl_type == F_WRLCK); |
248 | op->info.fsid = ls->id; | 278 | op->info.fsid = ls->ls_global_id; |
249 | op->info.number = name->ln_number; | 279 | op->info.number = number; |
250 | op->info.start = fl->fl_start; | 280 | op->info.start = fl->fl_start; |
251 | op->info.end = fl->fl_end; | 281 | op->info.end = fl->fl_end; |
252 | if (fl->fl_lmops && fl->fl_lmops->fl_grant) | 282 | if (fl->fl_lmops && fl->fl_lmops->fl_grant) |
@@ -259,7 +289,8 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name, | |||
259 | 289 | ||
260 | spin_lock(&ops_lock); | 290 | spin_lock(&ops_lock); |
261 | if (!list_empty(&op->list)) { | 291 | if (!list_empty(&op->list)) { |
262 | printk(KERN_INFO "plock_get op on list\n"); | 292 | log_error(ls, "dlm_posix_get: op on list %llx", |
293 | (unsigned long long)number); | ||
263 | list_del(&op->list); | 294 | list_del(&op->list); |
264 | } | 295 | } |
265 | spin_unlock(&ops_lock); | 296 | spin_unlock(&ops_lock); |
@@ -281,14 +312,17 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name, | |||
281 | } | 312 | } |
282 | 313 | ||
283 | kfree(op); | 314 | kfree(op); |
315 | out: | ||
316 | dlm_put_lockspace(ls); | ||
284 | return rv; | 317 | return rv; |
285 | } | 318 | } |
319 | EXPORT_SYMBOL_GPL(dlm_posix_get); | ||
286 | 320 | ||
287 | /* a read copies out one plock request from the send list */ | 321 | /* a read copies out one plock request from the send list */ |
288 | static ssize_t dev_read(struct file *file, char __user *u, size_t count, | 322 | static ssize_t dev_read(struct file *file, char __user *u, size_t count, |
289 | loff_t *ppos) | 323 | loff_t *ppos) |
290 | { | 324 | { |
291 | struct gdlm_plock_info info; | 325 | struct dlm_plock_info info; |
292 | struct plock_op *op = NULL; | 326 | struct plock_op *op = NULL; |
293 | 327 | ||
294 | if (count < sizeof(info)) | 328 | if (count < sizeof(info)) |
@@ -315,7 +349,7 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count, | |||
315 | static ssize_t dev_write(struct file *file, const char __user *u, size_t count, | 349 | static ssize_t dev_write(struct file *file, const char __user *u, size_t count, |
316 | loff_t *ppos) | 350 | loff_t *ppos) |
317 | { | 351 | { |
318 | struct gdlm_plock_info info; | 352 | struct dlm_plock_info info; |
319 | struct plock_op *op; | 353 | struct plock_op *op; |
320 | int found = 0; | 354 | int found = 0; |
321 | 355 | ||
@@ -345,12 +379,12 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, | |||
345 | struct plock_xop *xop; | 379 | struct plock_xop *xop; |
346 | xop = (struct plock_xop *)op; | 380 | xop = (struct plock_xop *)op; |
347 | if (xop->callback) | 381 | if (xop->callback) |
348 | count = gdlm_plock_callback(op); | 382 | count = dlm_plock_callback(op); |
349 | else | 383 | else |
350 | wake_up(&recv_wq); | 384 | wake_up(&recv_wq); |
351 | } else | 385 | } else |
352 | printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid, | 386 | log_print("dev_write no op %x %llx", info.fsid, |
353 | (unsigned long long)info.number); | 387 | (unsigned long long)info.number); |
354 | return count; | 388 | return count; |
355 | } | 389 | } |
356 | 390 | ||
@@ -377,11 +411,11 @@ static const struct file_operations dev_fops = { | |||
377 | 411 | ||
378 | static struct miscdevice plock_dev_misc = { | 412 | static struct miscdevice plock_dev_misc = { |
379 | .minor = MISC_DYNAMIC_MINOR, | 413 | .minor = MISC_DYNAMIC_MINOR, |
380 | .name = GDLM_PLOCK_MISC_NAME, | 414 | .name = DLM_PLOCK_MISC_NAME, |
381 | .fops = &dev_fops | 415 | .fops = &dev_fops |
382 | }; | 416 | }; |
383 | 417 | ||
384 | int gdlm_plock_init(void) | 418 | int dlm_plock_init(void) |
385 | { | 419 | { |
386 | int rv; | 420 | int rv; |
387 | 421 | ||
@@ -393,14 +427,13 @@ int gdlm_plock_init(void) | |||
393 | 427 | ||
394 | rv = misc_register(&plock_dev_misc); | 428 | rv = misc_register(&plock_dev_misc); |
395 | if (rv) | 429 | if (rv) |
396 | printk(KERN_INFO "gdlm_plock_init: misc_register failed %d", | 430 | log_print("dlm_plock_init: misc_register failed %d", rv); |
397 | rv); | ||
398 | return rv; | 431 | return rv; |
399 | } | 432 | } |
400 | 433 | ||
401 | void gdlm_plock_exit(void) | 434 | void dlm_plock_exit(void) |
402 | { | 435 | { |
403 | if (misc_deregister(&plock_dev_misc) < 0) | 436 | if (misc_deregister(&plock_dev_misc) < 0) |
404 | printk(KERN_INFO "gdlm_plock_exit: misc_deregister failed"); | 437 | log_print("dlm_plock_exit: misc_deregister failed"); |
405 | } | 438 | } |
406 | 439 | ||
diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c index 997f9531d594..fd677c8c3d3b 100644 --- a/fs/dlm/recoverd.c +++ b/fs/dlm/recoverd.c | |||
@@ -257,6 +257,7 @@ static void do_ls_recovery(struct dlm_ls *ls) | |||
257 | if (rv) { | 257 | if (rv) { |
258 | ls_recover(ls, rv); | 258 | ls_recover(ls, rv); |
259 | kfree(rv->nodeids); | 259 | kfree(rv->nodeids); |
260 | kfree(rv->new); | ||
260 | kfree(rv); | 261 | kfree(rv); |
261 | } | 262 | } |
262 | } | 263 | } |
@@ -953,7 +953,6 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
953 | { | 953 | { |
954 | char * name; | 954 | char * name; |
955 | int i, ch, retval; | 955 | int i, ch, retval; |
956 | struct files_struct *files; | ||
957 | char tcomm[sizeof(current->comm)]; | 956 | char tcomm[sizeof(current->comm)]; |
958 | 957 | ||
959 | /* | 958 | /* |
@@ -965,26 +964,15 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
965 | goto out; | 964 | goto out; |
966 | 965 | ||
967 | /* | 966 | /* |
968 | * Make sure we have private file handles. Ask the | ||
969 | * fork helper to do the work for us and the exit | ||
970 | * helper to do the cleanup of the old one. | ||
971 | */ | ||
972 | files = current->files; /* refcounted so safe to hold */ | ||
973 | retval = unshare_files(); | ||
974 | if (retval) | ||
975 | goto out; | ||
976 | /* | ||
977 | * Release all of the old mmap stuff | 967 | * Release all of the old mmap stuff |
978 | */ | 968 | */ |
979 | retval = exec_mmap(bprm->mm); | 969 | retval = exec_mmap(bprm->mm); |
980 | if (retval) | 970 | if (retval) |
981 | goto mmap_failed; | 971 | goto out; |
982 | 972 | ||
983 | bprm->mm = NULL; /* We're using it now */ | 973 | bprm->mm = NULL; /* We're using it now */ |
984 | 974 | ||
985 | /* This is the point of no return */ | 975 | /* This is the point of no return */ |
986 | put_files_struct(files); | ||
987 | |||
988 | current->sas_ss_sp = current->sas_ss_size = 0; | 976 | current->sas_ss_sp = current->sas_ss_size = 0; |
989 | 977 | ||
990 | if (current->euid == current->uid && current->egid == current->gid) | 978 | if (current->euid == current->uid && current->egid == current->gid) |
@@ -1034,8 +1022,6 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
1034 | 1022 | ||
1035 | return 0; | 1023 | return 0; |
1036 | 1024 | ||
1037 | mmap_failed: | ||
1038 | reset_files_struct(current, files); | ||
1039 | out: | 1025 | out: |
1040 | return retval; | 1026 | return retval; |
1041 | } | 1027 | } |
@@ -1283,12 +1269,17 @@ int do_execve(char * filename, | |||
1283 | struct linux_binprm *bprm; | 1269 | struct linux_binprm *bprm; |
1284 | struct file *file; | 1270 | struct file *file; |
1285 | unsigned long env_p; | 1271 | unsigned long env_p; |
1272 | struct files_struct *displaced; | ||
1286 | int retval; | 1273 | int retval; |
1287 | 1274 | ||
1275 | retval = unshare_files(&displaced); | ||
1276 | if (retval) | ||
1277 | goto out_ret; | ||
1278 | |||
1288 | retval = -ENOMEM; | 1279 | retval = -ENOMEM; |
1289 | bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); | 1280 | bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); |
1290 | if (!bprm) | 1281 | if (!bprm) |
1291 | goto out_ret; | 1282 | goto out_files; |
1292 | 1283 | ||
1293 | file = open_exec(filename); | 1284 | file = open_exec(filename); |
1294 | retval = PTR_ERR(file); | 1285 | retval = PTR_ERR(file); |
@@ -1343,6 +1334,8 @@ int do_execve(char * filename, | |||
1343 | security_bprm_free(bprm); | 1334 | security_bprm_free(bprm); |
1344 | acct_update_integrals(current); | 1335 | acct_update_integrals(current); |
1345 | kfree(bprm); | 1336 | kfree(bprm); |
1337 | if (displaced) | ||
1338 | put_files_struct(displaced); | ||
1346 | return retval; | 1339 | return retval; |
1347 | } | 1340 | } |
1348 | 1341 | ||
@@ -1363,6 +1356,9 @@ out_file: | |||
1363 | out_kfree: | 1356 | out_kfree: |
1364 | kfree(bprm); | 1357 | kfree(bprm); |
1365 | 1358 | ||
1359 | out_files: | ||
1360 | if (displaced) | ||
1361 | reset_files_struct(displaced); | ||
1366 | out_ret: | 1362 | out_ret: |
1367 | return retval; | 1363 | return retval; |
1368 | } | 1364 | } |
diff --git a/fs/fcntl.c b/fs/fcntl.c index e632da761fc1..3f3ac630ccde 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -55,14 +55,16 @@ static int get_close_on_exec(unsigned int fd) | |||
55 | * file_lock held for write. | 55 | * file_lock held for write. |
56 | */ | 56 | */ |
57 | 57 | ||
58 | static int locate_fd(struct files_struct *files, | 58 | static int locate_fd(unsigned int orig_start, int cloexec) |
59 | struct file *file, unsigned int orig_start) | ||
60 | { | 59 | { |
60 | struct files_struct *files = current->files; | ||
61 | unsigned int newfd; | 61 | unsigned int newfd; |
62 | unsigned int start; | 62 | unsigned int start; |
63 | int error; | 63 | int error; |
64 | struct fdtable *fdt; | 64 | struct fdtable *fdt; |
65 | 65 | ||
66 | spin_lock(&files->file_lock); | ||
67 | |||
66 | error = -EINVAL; | 68 | error = -EINVAL; |
67 | if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) | 69 | if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) |
68 | goto out; | 70 | goto out; |
@@ -97,42 +99,28 @@ repeat: | |||
97 | if (error) | 99 | if (error) |
98 | goto repeat; | 100 | goto repeat; |
99 | 101 | ||
100 | /* | ||
101 | * We reacquired files_lock, so we are safe as long as | ||
102 | * we reacquire the fdtable pointer and use it while holding | ||
103 | * the lock, no one can free it during that time. | ||
104 | */ | ||
105 | if (start <= files->next_fd) | 102 | if (start <= files->next_fd) |
106 | files->next_fd = newfd + 1; | 103 | files->next_fd = newfd + 1; |
107 | 104 | ||
105 | FD_SET(newfd, fdt->open_fds); | ||
106 | if (cloexec) | ||
107 | FD_SET(newfd, fdt->close_on_exec); | ||
108 | else | ||
109 | FD_CLR(newfd, fdt->close_on_exec); | ||
108 | error = newfd; | 110 | error = newfd; |
109 | 111 | ||
110 | out: | 112 | out: |
113 | spin_unlock(&files->file_lock); | ||
111 | return error; | 114 | return error; |
112 | } | 115 | } |
113 | 116 | ||
114 | static int dupfd(struct file *file, unsigned int start, int cloexec) | 117 | static int dupfd(struct file *file, unsigned int start, int cloexec) |
115 | { | 118 | { |
116 | struct files_struct * files = current->files; | 119 | int fd = locate_fd(start, cloexec); |
117 | struct fdtable *fdt; | 120 | if (fd >= 0) |
118 | int fd; | ||
119 | |||
120 | spin_lock(&files->file_lock); | ||
121 | fd = locate_fd(files, file, start); | ||
122 | if (fd >= 0) { | ||
123 | /* locate_fd() may have expanded fdtable, load the ptr */ | ||
124 | fdt = files_fdtable(files); | ||
125 | FD_SET(fd, fdt->open_fds); | ||
126 | if (cloexec) | ||
127 | FD_SET(fd, fdt->close_on_exec); | ||
128 | else | ||
129 | FD_CLR(fd, fdt->close_on_exec); | ||
130 | spin_unlock(&files->file_lock); | ||
131 | fd_install(fd, file); | 121 | fd_install(fd, file); |
132 | } else { | 122 | else |
133 | spin_unlock(&files->file_lock); | ||
134 | fput(file); | 123 | fput(file); |
135 | } | ||
136 | 124 | ||
137 | return fd; | 125 | return fd; |
138 | } | 126 | } |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 033f7bdd47e8..4df34da2284a 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -242,10 +242,9 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, | |||
242 | return inode; | 242 | return inode; |
243 | } | 243 | } |
244 | 244 | ||
245 | static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags) | 245 | static void fuse_umount_begin(struct super_block *sb) |
246 | { | 246 | { |
247 | if (flags & MNT_FORCE) | 247 | fuse_abort_conn(get_fuse_conn_super(sb)); |
248 | fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb)); | ||
249 | } | 248 | } |
250 | 249 | ||
251 | static void fuse_send_destroy(struct fuse_conn *fc) | 250 | static void fuse_send_destroy(struct fuse_conn *fc) |
diff --git a/fs/gfs2/locking/dlm/Makefile b/fs/gfs2/locking/dlm/Makefile index 89b93b6b45cf..2609bb6cd013 100644 --- a/fs/gfs2/locking/dlm/Makefile +++ b/fs/gfs2/locking/dlm/Makefile | |||
@@ -1,3 +1,3 @@ | |||
1 | obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += lock_dlm.o | 1 | obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += lock_dlm.o |
2 | lock_dlm-y := lock.o main.o mount.o sysfs.o thread.o plock.o | 2 | lock_dlm-y := lock.o main.o mount.o sysfs.o thread.o |
3 | 3 | ||
diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h index 58fcf8c5bf39..a243cf69c54e 100644 --- a/fs/gfs2/locking/dlm/lock_dlm.h +++ b/fs/gfs2/locking/dlm/lock_dlm.h | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <net/sock.h> | 25 | #include <net/sock.h> |
26 | 26 | ||
27 | #include <linux/dlm.h> | 27 | #include <linux/dlm.h> |
28 | #include <linux/dlm_plock.h> | ||
28 | #include <linux/lm_interface.h> | 29 | #include <linux/lm_interface.h> |
29 | 30 | ||
30 | /* | 31 | /* |
@@ -173,17 +174,6 @@ void gdlm_cancel(void *); | |||
173 | int gdlm_hold_lvb(void *, char **); | 174 | int gdlm_hold_lvb(void *, char **); |
174 | void gdlm_unhold_lvb(void *, char *); | 175 | void gdlm_unhold_lvb(void *, char *); |
175 | 176 | ||
176 | /* plock.c */ | ||
177 | |||
178 | int gdlm_plock_init(void); | ||
179 | void gdlm_plock_exit(void); | ||
180 | int gdlm_plock(void *, struct lm_lockname *, struct file *, int, | ||
181 | struct file_lock *); | ||
182 | int gdlm_plock_get(void *, struct lm_lockname *, struct file *, | ||
183 | struct file_lock *); | ||
184 | int gdlm_punlock(void *, struct lm_lockname *, struct file *, | ||
185 | struct file_lock *); | ||
186 | |||
187 | /* mount.c */ | 177 | /* mount.c */ |
188 | 178 | ||
189 | extern const struct lm_lockops gdlm_ops; | 179 | extern const struct lm_lockops gdlm_ops; |
diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c index 36a225850bd8..b9a03a7ff801 100644 --- a/fs/gfs2/locking/dlm/main.c +++ b/fs/gfs2/locking/dlm/main.c | |||
@@ -28,13 +28,6 @@ static int __init init_lock_dlm(void) | |||
28 | return error; | 28 | return error; |
29 | } | 29 | } |
30 | 30 | ||
31 | error = gdlm_plock_init(); | ||
32 | if (error) { | ||
33 | gdlm_sysfs_exit(); | ||
34 | gfs2_unregister_lockproto(&gdlm_ops); | ||
35 | return error; | ||
36 | } | ||
37 | |||
38 | printk(KERN_INFO | 31 | printk(KERN_INFO |
39 | "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__); | 32 | "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__); |
40 | return 0; | 33 | return 0; |
@@ -42,7 +35,6 @@ static int __init init_lock_dlm(void) | |||
42 | 35 | ||
43 | static void __exit exit_lock_dlm(void) | 36 | static void __exit exit_lock_dlm(void) |
44 | { | 37 | { |
45 | gdlm_plock_exit(); | ||
46 | gdlm_sysfs_exit(); | 38 | gdlm_sysfs_exit(); |
47 | gfs2_unregister_lockproto(&gdlm_ops); | 39 | gfs2_unregister_lockproto(&gdlm_ops); |
48 | } | 40 | } |
diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c index f2efff424224..470bdf650b50 100644 --- a/fs/gfs2/locking/dlm/mount.c +++ b/fs/gfs2/locking/dlm/mount.c | |||
@@ -236,6 +236,27 @@ static void gdlm_withdraw(void *lockspace) | |||
236 | gdlm_kobject_release(ls); | 236 | gdlm_kobject_release(ls); |
237 | } | 237 | } |
238 | 238 | ||
239 | static int gdlm_plock(void *lockspace, struct lm_lockname *name, | ||
240 | struct file *file, int cmd, struct file_lock *fl) | ||
241 | { | ||
242 | struct gdlm_ls *ls = lockspace; | ||
243 | return dlm_posix_lock(ls->dlm_lockspace, name->ln_number, file, cmd, fl); | ||
244 | } | ||
245 | |||
246 | static int gdlm_punlock(void *lockspace, struct lm_lockname *name, | ||
247 | struct file *file, struct file_lock *fl) | ||
248 | { | ||
249 | struct gdlm_ls *ls = lockspace; | ||
250 | return dlm_posix_unlock(ls->dlm_lockspace, name->ln_number, file, fl); | ||
251 | } | ||
252 | |||
253 | static int gdlm_plock_get(void *lockspace, struct lm_lockname *name, | ||
254 | struct file *file, struct file_lock *fl) | ||
255 | { | ||
256 | struct gdlm_ls *ls = lockspace; | ||
257 | return dlm_posix_get(ls->dlm_lockspace, name->ln_number, file, fl); | ||
258 | } | ||
259 | |||
239 | const struct lm_lockops gdlm_ops = { | 260 | const struct lm_lockops gdlm_ops = { |
240 | .lm_proto_name = "lock_dlm", | 261 | .lm_proto_name = "lock_dlm", |
241 | .lm_mount = gdlm_mount, | 262 | .lm_mount = gdlm_mount, |
diff --git a/fs/internal.h b/fs/internal.h index 392e8ccd6fc4..80aa9a023372 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -43,3 +43,14 @@ extern void __init chrdev_init(void); | |||
43 | * namespace.c | 43 | * namespace.c |
44 | */ | 44 | */ |
45 | extern int copy_mount_options(const void __user *, unsigned long *); | 45 | extern int copy_mount_options(const void __user *, unsigned long *); |
46 | |||
47 | extern void free_vfsmnt(struct vfsmount *); | ||
48 | extern struct vfsmount *alloc_vfsmnt(const char *); | ||
49 | extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int); | ||
50 | extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *, | ||
51 | struct vfsmount *); | ||
52 | extern void release_mounts(struct list_head *); | ||
53 | extern void umount_tree(struct vfsmount *, int, struct list_head *); | ||
54 | extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); | ||
55 | |||
56 | extern void __init mnt_init(void); | ||
diff --git a/fs/jffs2/README.Locking b/fs/jffs2/README.Locking index d14d5a4dc5ac..3ea36554107f 100644 --- a/fs/jffs2/README.Locking +++ b/fs/jffs2/README.Locking | |||
@@ -14,7 +14,7 @@ be fairly close. | |||
14 | alloc_sem | 14 | alloc_sem |
15 | --------- | 15 | --------- |
16 | 16 | ||
17 | The alloc_sem is a per-filesystem semaphore, used primarily to ensure | 17 | The alloc_sem is a per-filesystem mutex, used primarily to ensure |
18 | contiguous allocation of space on the medium. It is automatically | 18 | contiguous allocation of space on the medium. It is automatically |
19 | obtained during space allocations (jffs2_reserve_space()) and freed | 19 | obtained during space allocations (jffs2_reserve_space()) and freed |
20 | upon write completion (jffs2_complete_reservation()). Note that | 20 | upon write completion (jffs2_complete_reservation()). Note that |
@@ -41,10 +41,10 @@ if the wbuf is currently holding any data is permitted, though. | |||
41 | Ordering constraints: See f->sem. | 41 | Ordering constraints: See f->sem. |
42 | 42 | ||
43 | 43 | ||
44 | File Semaphore f->sem | 44 | File Mutex f->sem |
45 | --------------------- | 45 | --------------------- |
46 | 46 | ||
47 | This is the JFFS2-internal equivalent of the inode semaphore i->i_sem. | 47 | This is the JFFS2-internal equivalent of the inode mutex i->i_sem. |
48 | It protects the contents of the jffs2_inode_info private inode data, | 48 | It protects the contents of the jffs2_inode_info private inode data, |
49 | including the linked list of node fragments (but see the notes below on | 49 | including the linked list of node fragments (but see the notes below on |
50 | erase_completion_lock), etc. | 50 | erase_completion_lock), etc. |
@@ -60,14 +60,14 @@ lead to deadlock, unless we played games with unlocking the i_sem | |||
60 | before calling the space allocation functions. | 60 | before calling the space allocation functions. |
61 | 61 | ||
62 | Instead of playing such games, we just have an extra internal | 62 | Instead of playing such games, we just have an extra internal |
63 | semaphore, which is obtained by the garbage collection code and also | 63 | mutex, which is obtained by the garbage collection code and also |
64 | by the normal file system code _after_ allocation of space. | 64 | by the normal file system code _after_ allocation of space. |
65 | 65 | ||
66 | Ordering constraints: | 66 | Ordering constraints: |
67 | 67 | ||
68 | 1. Never attempt to allocate space or lock alloc_sem with | 68 | 1. Never attempt to allocate space or lock alloc_sem with |
69 | any f->sem held. | 69 | any f->sem held. |
70 | 2. Never attempt to lock two file semaphores in one thread. | 70 | 2. Never attempt to lock two file mutexes in one thread. |
71 | No ordering rules have been made for doing so. | 71 | No ordering rules have been made for doing so. |
72 | 72 | ||
73 | 73 | ||
@@ -86,8 +86,8 @@ a simple spin_lock() rather than spin_lock_bh(). | |||
86 | 86 | ||
87 | Note that the per-inode list of physical nodes (f->nodes) is a special | 87 | Note that the per-inode list of physical nodes (f->nodes) is a special |
88 | case. Any changes to _valid_ nodes (i.e. ->flash_offset & 1 == 0) in | 88 | case. Any changes to _valid_ nodes (i.e. ->flash_offset & 1 == 0) in |
89 | the list are protected by the file semaphore f->sem. But the erase | 89 | the list are protected by the file mutex f->sem. But the erase code |
90 | code may remove _obsolete_ nodes from the list while holding only the | 90 | may remove _obsolete_ nodes from the list while holding only the |
91 | erase_completion_lock. So you can walk the list only while holding the | 91 | erase_completion_lock. So you can walk the list only while holding the |
92 | erase_completion_lock, and can drop the lock temporarily mid-walk as | 92 | erase_completion_lock, and can drop the lock temporarily mid-walk as |
93 | long as the pointer you're holding is to a _valid_ node, not an | 93 | long as the pointer you're holding is to a _valid_ node, not an |
@@ -124,10 +124,10 @@ Ordering constraints: | |||
124 | erase_free_sem | 124 | erase_free_sem |
125 | -------------- | 125 | -------------- |
126 | 126 | ||
127 | This semaphore is only used by the erase code which frees obsolete | 127 | This mutex is only used by the erase code which frees obsolete node |
128 | node references and the jffs2_garbage_collect_deletion_dirent() | 128 | references and the jffs2_garbage_collect_deletion_dirent() function. |
129 | function. The latter function on NAND flash must read _obsolete_ nodes | 129 | The latter function on NAND flash must read _obsolete_ nodes to |
130 | to determine whether the 'deletion dirent' under consideration can be | 130 | determine whether the 'deletion dirent' under consideration can be |
131 | discarded or whether it is still required to show that an inode has | 131 | discarded or whether it is still required to show that an inode has |
132 | been unlinked. Because reading from the flash may sleep, the | 132 | been unlinked. Because reading from the flash may sleep, the |
133 | erase_completion_lock cannot be held, so an alternative, more | 133 | erase_completion_lock cannot be held, so an alternative, more |
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 722a6b682951..d58f845ccb85 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c | |||
@@ -345,6 +345,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c) | |||
345 | INIT_LIST_HEAD(&c->dirty_list); | 345 | INIT_LIST_HEAD(&c->dirty_list); |
346 | INIT_LIST_HEAD(&c->erasable_list); | 346 | INIT_LIST_HEAD(&c->erasable_list); |
347 | INIT_LIST_HEAD(&c->erasing_list); | 347 | INIT_LIST_HEAD(&c->erasing_list); |
348 | INIT_LIST_HEAD(&c->erase_checking_list); | ||
348 | INIT_LIST_HEAD(&c->erase_pending_list); | 349 | INIT_LIST_HEAD(&c->erase_pending_list); |
349 | INIT_LIST_HEAD(&c->erasable_pending_wbuf_list); | 350 | INIT_LIST_HEAD(&c->erasable_pending_wbuf_list); |
350 | INIT_LIST_HEAD(&c->erase_complete_list); | 351 | INIT_LIST_HEAD(&c->erase_complete_list); |
diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c index 3a32c64ed497..5544d31c066b 100644 --- a/fs/jffs2/debug.c +++ b/fs/jffs2/debug.c | |||
@@ -62,9 +62,9 @@ __jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c, | |||
62 | void | 62 | void |
63 | __jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f) | 63 | __jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f) |
64 | { | 64 | { |
65 | down(&f->sem); | 65 | mutex_lock(&f->sem); |
66 | __jffs2_dbg_fragtree_paranoia_check_nolock(f); | 66 | __jffs2_dbg_fragtree_paranoia_check_nolock(f); |
67 | up(&f->sem); | 67 | mutex_unlock(&f->sem); |
68 | } | 68 | } |
69 | 69 | ||
70 | void | 70 | void |
@@ -153,6 +153,139 @@ __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c, | |||
153 | kfree(buf); | 153 | kfree(buf); |
154 | } | 154 | } |
155 | 155 | ||
156 | void __jffs2_dbg_superblock_counts(struct jffs2_sb_info *c) | ||
157 | { | ||
158 | struct jffs2_eraseblock *jeb; | ||
159 | uint32_t free = 0, dirty = 0, used = 0, wasted = 0, | ||
160 | erasing = 0, bad = 0, unchecked = 0; | ||
161 | int nr_counted = 0; | ||
162 | int dump = 0; | ||
163 | |||
164 | if (c->gcblock) { | ||
165 | nr_counted++; | ||
166 | free += c->gcblock->free_size; | ||
167 | dirty += c->gcblock->dirty_size; | ||
168 | used += c->gcblock->used_size; | ||
169 | wasted += c->gcblock->wasted_size; | ||
170 | unchecked += c->gcblock->unchecked_size; | ||
171 | } | ||
172 | if (c->nextblock) { | ||
173 | nr_counted++; | ||
174 | free += c->nextblock->free_size; | ||
175 | dirty += c->nextblock->dirty_size; | ||
176 | used += c->nextblock->used_size; | ||
177 | wasted += c->nextblock->wasted_size; | ||
178 | unchecked += c->nextblock->unchecked_size; | ||
179 | } | ||
180 | list_for_each_entry(jeb, &c->clean_list, list) { | ||
181 | nr_counted++; | ||
182 | free += jeb->free_size; | ||
183 | dirty += jeb->dirty_size; | ||
184 | used += jeb->used_size; | ||
185 | wasted += jeb->wasted_size; | ||
186 | unchecked += jeb->unchecked_size; | ||
187 | } | ||
188 | list_for_each_entry(jeb, &c->very_dirty_list, list) { | ||
189 | nr_counted++; | ||
190 | free += jeb->free_size; | ||
191 | dirty += jeb->dirty_size; | ||
192 | used += jeb->used_size; | ||
193 | wasted += jeb->wasted_size; | ||
194 | unchecked += jeb->unchecked_size; | ||
195 | } | ||
196 | list_for_each_entry(jeb, &c->dirty_list, list) { | ||
197 | nr_counted++; | ||
198 | free += jeb->free_size; | ||
199 | dirty += jeb->dirty_size; | ||
200 | used += jeb->used_size; | ||
201 | wasted += jeb->wasted_size; | ||
202 | unchecked += jeb->unchecked_size; | ||
203 | } | ||
204 | list_for_each_entry(jeb, &c->erasable_list, list) { | ||
205 | nr_counted++; | ||
206 | free += jeb->free_size; | ||
207 | dirty += jeb->dirty_size; | ||
208 | used += jeb->used_size; | ||
209 | wasted += jeb->wasted_size; | ||
210 | unchecked += jeb->unchecked_size; | ||
211 | } | ||
212 | list_for_each_entry(jeb, &c->erasable_pending_wbuf_list, list) { | ||
213 | nr_counted++; | ||
214 | free += jeb->free_size; | ||
215 | dirty += jeb->dirty_size; | ||
216 | used += jeb->used_size; | ||
217 | wasted += jeb->wasted_size; | ||
218 | unchecked += jeb->unchecked_size; | ||
219 | } | ||
220 | list_for_each_entry(jeb, &c->erase_pending_list, list) { | ||
221 | nr_counted++; | ||
222 | free += jeb->free_size; | ||
223 | dirty += jeb->dirty_size; | ||
224 | used += jeb->used_size; | ||
225 | wasted += jeb->wasted_size; | ||
226 | unchecked += jeb->unchecked_size; | ||
227 | } | ||
228 | list_for_each_entry(jeb, &c->free_list, list) { | ||
229 | nr_counted++; | ||
230 | free += jeb->free_size; | ||
231 | dirty += jeb->dirty_size; | ||
232 | used += jeb->used_size; | ||
233 | wasted += jeb->wasted_size; | ||
234 | unchecked += jeb->unchecked_size; | ||
235 | } | ||
236 | list_for_each_entry(jeb, &c->bad_used_list, list) { | ||
237 | nr_counted++; | ||
238 | free += jeb->free_size; | ||
239 | dirty += jeb->dirty_size; | ||
240 | used += jeb->used_size; | ||
241 | wasted += jeb->wasted_size; | ||
242 | unchecked += jeb->unchecked_size; | ||
243 | } | ||
244 | |||
245 | list_for_each_entry(jeb, &c->erasing_list, list) { | ||
246 | nr_counted++; | ||
247 | erasing += c->sector_size; | ||
248 | } | ||
249 | list_for_each_entry(jeb, &c->erase_checking_list, list) { | ||
250 | nr_counted++; | ||
251 | erasing += c->sector_size; | ||
252 | } | ||
253 | list_for_each_entry(jeb, &c->erase_complete_list, list) { | ||
254 | nr_counted++; | ||
255 | erasing += c->sector_size; | ||
256 | } | ||
257 | list_for_each_entry(jeb, &c->bad_list, list) { | ||
258 | nr_counted++; | ||
259 | bad += c->sector_size; | ||
260 | } | ||
261 | |||
262 | #define check(sz) \ | ||
263 | if (sz != c->sz##_size) { \ | ||
264 | printk(KERN_WARNING #sz "_size mismatch counted 0x%x, c->" #sz "_size 0x%x\n", \ | ||
265 | sz, c->sz##_size); \ | ||
266 | dump = 1; \ | ||
267 | } | ||
268 | check(free); | ||
269 | check(dirty); | ||
270 | check(used); | ||
271 | check(wasted); | ||
272 | check(unchecked); | ||
273 | check(bad); | ||
274 | check(erasing); | ||
275 | #undef check | ||
276 | |||
277 | if (nr_counted != c->nr_blocks) { | ||
278 | printk(KERN_WARNING "%s counted only 0x%x blocks of 0x%x. Where are the others?\n", | ||
279 | __func__, nr_counted, c->nr_blocks); | ||
280 | dump = 1; | ||
281 | } | ||
282 | |||
283 | if (dump) { | ||
284 | __jffs2_dbg_dump_block_lists_nolock(c); | ||
285 | BUG(); | ||
286 | } | ||
287 | } | ||
288 | |||
156 | /* | 289 | /* |
157 | * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'. | 290 | * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'. |
158 | */ | 291 | */ |
@@ -229,6 +362,9 @@ __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c, | |||
229 | } | 362 | } |
230 | #endif | 363 | #endif |
231 | 364 | ||
365 | if (!(c->flags & (JFFS2_SB_FLAG_BUILDING|JFFS2_SB_FLAG_SCANNING))) | ||
366 | __jffs2_dbg_superblock_counts(c); | ||
367 | |||
232 | return; | 368 | return; |
233 | 369 | ||
234 | error: | 370 | error: |
@@ -268,7 +404,10 @@ __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c, | |||
268 | 404 | ||
269 | printk(JFFS2_DBG); | 405 | printk(JFFS2_DBG); |
270 | for (ref = jeb->first_node; ; ref = ref_next(ref)) { | 406 | for (ref = jeb->first_node; ; ref = ref_next(ref)) { |
271 | printk("%#08x(%#x)", ref_offset(ref), ref->__totlen); | 407 | printk("%#08x", ref_offset(ref)); |
408 | #ifdef TEST_TOTLEN | ||
409 | printk("(%x)", ref->__totlen); | ||
410 | #endif | ||
272 | if (ref_next(ref)) | 411 | if (ref_next(ref)) |
273 | printk("->"); | 412 | printk("->"); |
274 | else | 413 | else |
@@ -447,6 +586,21 @@ __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c) | |||
447 | } | 586 | } |
448 | } | 587 | } |
449 | } | 588 | } |
589 | if (list_empty(&c->erase_checking_list)) { | ||
590 | printk(JFFS2_DBG "erase_checking_list: empty\n"); | ||
591 | } else { | ||
592 | struct list_head *this; | ||
593 | |||
594 | list_for_each(this, &c->erase_checking_list) { | ||
595 | struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); | ||
596 | |||
597 | if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) { | ||
598 | printk(JFFS2_DBG "erase_checking_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n", | ||
599 | jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, | ||
600 | jeb->unchecked_size, jeb->free_size); | ||
601 | } | ||
602 | } | ||
603 | } | ||
450 | 604 | ||
451 | if (list_empty(&c->erase_pending_list)) { | 605 | if (list_empty(&c->erase_pending_list)) { |
452 | printk(JFFS2_DBG "erase_pending_list: empty\n"); | 606 | printk(JFFS2_DBG "erase_pending_list: empty\n"); |
@@ -532,9 +686,9 @@ __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c) | |||
532 | void | 686 | void |
533 | __jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f) | 687 | __jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f) |
534 | { | 688 | { |
535 | down(&f->sem); | 689 | mutex_lock(&f->sem); |
536 | jffs2_dbg_dump_fragtree_nolock(f); | 690 | jffs2_dbg_dump_fragtree_nolock(f); |
537 | up(&f->sem); | 691 | mutex_unlock(&f->sem); |
538 | } | 692 | } |
539 | 693 | ||
540 | void | 694 | void |
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h index 4130adabd76e..9645275023e6 100644 --- a/fs/jffs2/debug.h +++ b/fs/jffs2/debug.h | |||
@@ -38,6 +38,7 @@ | |||
38 | 38 | ||
39 | #if CONFIG_JFFS2_FS_DEBUG > 1 | 39 | #if CONFIG_JFFS2_FS_DEBUG > 1 |
40 | #define JFFS2_DBG_FRAGTREE2_MESSAGES | 40 | #define JFFS2_DBG_FRAGTREE2_MESSAGES |
41 | #define JFFS2_DBG_READINODE2_MESSAGES | ||
41 | #define JFFS2_DBG_MEMALLOC_MESSAGES | 42 | #define JFFS2_DBG_MEMALLOC_MESSAGES |
42 | #endif | 43 | #endif |
43 | 44 | ||
@@ -115,6 +116,11 @@ | |||
115 | #else | 116 | #else |
116 | #define dbg_readinode(fmt, ...) | 117 | #define dbg_readinode(fmt, ...) |
117 | #endif | 118 | #endif |
119 | #ifdef JFFS2_DBG_READINODE2_MESSAGES | ||
120 | #define dbg_readinode2(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) | ||
121 | #else | ||
122 | #define dbg_readinode2(fmt, ...) | ||
123 | #endif | ||
118 | 124 | ||
119 | /* Fragtree build debugging messages */ | 125 | /* Fragtree build debugging messages */ |
120 | #ifdef JFFS2_DBG_FRAGTREE_MESSAGES | 126 | #ifdef JFFS2_DBG_FRAGTREE_MESSAGES |
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index f948f7e6ec82..c63e7a96af0d 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c | |||
@@ -86,7 +86,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, | |||
86 | dir_f = JFFS2_INODE_INFO(dir_i); | 86 | dir_f = JFFS2_INODE_INFO(dir_i); |
87 | c = JFFS2_SB_INFO(dir_i->i_sb); | 87 | c = JFFS2_SB_INFO(dir_i->i_sb); |
88 | 88 | ||
89 | down(&dir_f->sem); | 89 | mutex_lock(&dir_f->sem); |
90 | 90 | ||
91 | /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */ | 91 | /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */ |
92 | for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) { | 92 | for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) { |
@@ -99,7 +99,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, | |||
99 | } | 99 | } |
100 | if (fd) | 100 | if (fd) |
101 | ino = fd->ino; | 101 | ino = fd->ino; |
102 | up(&dir_f->sem); | 102 | mutex_unlock(&dir_f->sem); |
103 | if (ino) { | 103 | if (ino) { |
104 | inode = jffs2_iget(dir_i->i_sb, ino); | 104 | inode = jffs2_iget(dir_i->i_sb, ino); |
105 | if (IS_ERR(inode)) { | 105 | if (IS_ERR(inode)) { |
@@ -146,7 +146,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
146 | } | 146 | } |
147 | 147 | ||
148 | curofs=1; | 148 | curofs=1; |
149 | down(&f->sem); | 149 | mutex_lock(&f->sem); |
150 | for (fd = f->dents; fd; fd = fd->next) { | 150 | for (fd = f->dents; fd; fd = fd->next) { |
151 | 151 | ||
152 | curofs++; | 152 | curofs++; |
@@ -166,7 +166,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
166 | break; | 166 | break; |
167 | offset++; | 167 | offset++; |
168 | } | 168 | } |
169 | up(&f->sem); | 169 | mutex_unlock(&f->sem); |
170 | out: | 170 | out: |
171 | filp->f_pos = offset; | 171 | filp->f_pos = offset; |
172 | return 0; | 172 | return 0; |
@@ -275,9 +275,9 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de | |||
275 | ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now); | 275 | ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now); |
276 | 276 | ||
277 | if (!ret) { | 277 | if (!ret) { |
278 | down(&f->sem); | 278 | mutex_lock(&f->sem); |
279 | old_dentry->d_inode->i_nlink = ++f->inocache->nlink; | 279 | old_dentry->d_inode->i_nlink = ++f->inocache->nlink; |
280 | up(&f->sem); | 280 | mutex_unlock(&f->sem); |
281 | d_instantiate(dentry, old_dentry->d_inode); | 281 | d_instantiate(dentry, old_dentry->d_inode); |
282 | dir_i->i_mtime = dir_i->i_ctime = ITIME(now); | 282 | dir_i->i_mtime = dir_i->i_ctime = ITIME(now); |
283 | atomic_inc(&old_dentry->d_inode->i_count); | 283 | atomic_inc(&old_dentry->d_inode->i_count); |
@@ -351,7 +351,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
351 | 351 | ||
352 | if (IS_ERR(fn)) { | 352 | if (IS_ERR(fn)) { |
353 | /* Eeek. Wave bye bye */ | 353 | /* Eeek. Wave bye bye */ |
354 | up(&f->sem); | 354 | mutex_unlock(&f->sem); |
355 | jffs2_complete_reservation(c); | 355 | jffs2_complete_reservation(c); |
356 | jffs2_clear_inode(inode); | 356 | jffs2_clear_inode(inode); |
357 | return PTR_ERR(fn); | 357 | return PTR_ERR(fn); |
@@ -361,7 +361,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
361 | f->target = kmalloc(targetlen + 1, GFP_KERNEL); | 361 | f->target = kmalloc(targetlen + 1, GFP_KERNEL); |
362 | if (!f->target) { | 362 | if (!f->target) { |
363 | printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); | 363 | printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); |
364 | up(&f->sem); | 364 | mutex_unlock(&f->sem); |
365 | jffs2_complete_reservation(c); | 365 | jffs2_complete_reservation(c); |
366 | jffs2_clear_inode(inode); | 366 | jffs2_clear_inode(inode); |
367 | return -ENOMEM; | 367 | return -ENOMEM; |
@@ -374,7 +374,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
374 | obsoleted by the first data write | 374 | obsoleted by the first data write |
375 | */ | 375 | */ |
376 | f->metadata = fn; | 376 | f->metadata = fn; |
377 | up(&f->sem); | 377 | mutex_unlock(&f->sem); |
378 | 378 | ||
379 | jffs2_complete_reservation(c); | 379 | jffs2_complete_reservation(c); |
380 | 380 | ||
@@ -406,7 +406,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
406 | } | 406 | } |
407 | 407 | ||
408 | dir_f = JFFS2_INODE_INFO(dir_i); | 408 | dir_f = JFFS2_INODE_INFO(dir_i); |
409 | down(&dir_f->sem); | 409 | mutex_lock(&dir_f->sem); |
410 | 410 | ||
411 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 411 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
412 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); | 412 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); |
@@ -429,7 +429,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
429 | as if it were the final unlink() */ | 429 | as if it were the final unlink() */ |
430 | jffs2_complete_reservation(c); | 430 | jffs2_complete_reservation(c); |
431 | jffs2_free_raw_dirent(rd); | 431 | jffs2_free_raw_dirent(rd); |
432 | up(&dir_f->sem); | 432 | mutex_unlock(&dir_f->sem); |
433 | jffs2_clear_inode(inode); | 433 | jffs2_clear_inode(inode); |
434 | return PTR_ERR(fd); | 434 | return PTR_ERR(fd); |
435 | } | 435 | } |
@@ -442,7 +442,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
442 | one if necessary. */ | 442 | one if necessary. */ |
443 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | 443 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); |
444 | 444 | ||
445 | up(&dir_f->sem); | 445 | mutex_unlock(&dir_f->sem); |
446 | jffs2_complete_reservation(c); | 446 | jffs2_complete_reservation(c); |
447 | 447 | ||
448 | d_instantiate(dentry, inode); | 448 | d_instantiate(dentry, inode); |
@@ -507,7 +507,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
507 | 507 | ||
508 | if (IS_ERR(fn)) { | 508 | if (IS_ERR(fn)) { |
509 | /* Eeek. Wave bye bye */ | 509 | /* Eeek. Wave bye bye */ |
510 | up(&f->sem); | 510 | mutex_unlock(&f->sem); |
511 | jffs2_complete_reservation(c); | 511 | jffs2_complete_reservation(c); |
512 | jffs2_clear_inode(inode); | 512 | jffs2_clear_inode(inode); |
513 | return PTR_ERR(fn); | 513 | return PTR_ERR(fn); |
@@ -516,7 +516,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
516 | obsoleted by the first data write | 516 | obsoleted by the first data write |
517 | */ | 517 | */ |
518 | f->metadata = fn; | 518 | f->metadata = fn; |
519 | up(&f->sem); | 519 | mutex_unlock(&f->sem); |
520 | 520 | ||
521 | jffs2_complete_reservation(c); | 521 | jffs2_complete_reservation(c); |
522 | 522 | ||
@@ -548,7 +548,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
548 | } | 548 | } |
549 | 549 | ||
550 | dir_f = JFFS2_INODE_INFO(dir_i); | 550 | dir_f = JFFS2_INODE_INFO(dir_i); |
551 | down(&dir_f->sem); | 551 | mutex_lock(&dir_f->sem); |
552 | 552 | ||
553 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 553 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
554 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); | 554 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); |
@@ -571,7 +571,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
571 | as if it were the final unlink() */ | 571 | as if it were the final unlink() */ |
572 | jffs2_complete_reservation(c); | 572 | jffs2_complete_reservation(c); |
573 | jffs2_free_raw_dirent(rd); | 573 | jffs2_free_raw_dirent(rd); |
574 | up(&dir_f->sem); | 574 | mutex_unlock(&dir_f->sem); |
575 | jffs2_clear_inode(inode); | 575 | jffs2_clear_inode(inode); |
576 | return PTR_ERR(fd); | 576 | return PTR_ERR(fd); |
577 | } | 577 | } |
@@ -585,7 +585,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
585 | one if necessary. */ | 585 | one if necessary. */ |
586 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | 586 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); |
587 | 587 | ||
588 | up(&dir_f->sem); | 588 | mutex_unlock(&dir_f->sem); |
589 | jffs2_complete_reservation(c); | 589 | jffs2_complete_reservation(c); |
590 | 590 | ||
591 | d_instantiate(dentry, inode); | 591 | d_instantiate(dentry, inode); |
@@ -673,7 +673,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
673 | 673 | ||
674 | if (IS_ERR(fn)) { | 674 | if (IS_ERR(fn)) { |
675 | /* Eeek. Wave bye bye */ | 675 | /* Eeek. Wave bye bye */ |
676 | up(&f->sem); | 676 | mutex_unlock(&f->sem); |
677 | jffs2_complete_reservation(c); | 677 | jffs2_complete_reservation(c); |
678 | jffs2_clear_inode(inode); | 678 | jffs2_clear_inode(inode); |
679 | return PTR_ERR(fn); | 679 | return PTR_ERR(fn); |
@@ -682,7 +682,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
682 | obsoleted by the first data write | 682 | obsoleted by the first data write |
683 | */ | 683 | */ |
684 | f->metadata = fn; | 684 | f->metadata = fn; |
685 | up(&f->sem); | 685 | mutex_unlock(&f->sem); |
686 | 686 | ||
687 | jffs2_complete_reservation(c); | 687 | jffs2_complete_reservation(c); |
688 | 688 | ||
@@ -714,7 +714,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
714 | } | 714 | } |
715 | 715 | ||
716 | dir_f = JFFS2_INODE_INFO(dir_i); | 716 | dir_f = JFFS2_INODE_INFO(dir_i); |
717 | down(&dir_f->sem); | 717 | mutex_lock(&dir_f->sem); |
718 | 718 | ||
719 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 719 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
720 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); | 720 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); |
@@ -740,7 +740,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
740 | as if it were the final unlink() */ | 740 | as if it were the final unlink() */ |
741 | jffs2_complete_reservation(c); | 741 | jffs2_complete_reservation(c); |
742 | jffs2_free_raw_dirent(rd); | 742 | jffs2_free_raw_dirent(rd); |
743 | up(&dir_f->sem); | 743 | mutex_unlock(&dir_f->sem); |
744 | jffs2_clear_inode(inode); | 744 | jffs2_clear_inode(inode); |
745 | return PTR_ERR(fd); | 745 | return PTR_ERR(fd); |
746 | } | 746 | } |
@@ -753,7 +753,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
753 | one if necessary. */ | 753 | one if necessary. */ |
754 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | 754 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); |
755 | 755 | ||
756 | up(&dir_f->sem); | 756 | mutex_unlock(&dir_f->sem); |
757 | jffs2_complete_reservation(c); | 757 | jffs2_complete_reservation(c); |
758 | 758 | ||
759 | d_instantiate(dentry, inode); | 759 | d_instantiate(dentry, inode); |
@@ -780,14 +780,14 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | |||
780 | if (S_ISDIR(new_dentry->d_inode->i_mode)) { | 780 | if (S_ISDIR(new_dentry->d_inode->i_mode)) { |
781 | struct jffs2_full_dirent *fd; | 781 | struct jffs2_full_dirent *fd; |
782 | 782 | ||
783 | down(&victim_f->sem); | 783 | mutex_lock(&victim_f->sem); |
784 | for (fd = victim_f->dents; fd; fd = fd->next) { | 784 | for (fd = victim_f->dents; fd; fd = fd->next) { |
785 | if (fd->ino) { | 785 | if (fd->ino) { |
786 | up(&victim_f->sem); | 786 | mutex_unlock(&victim_f->sem); |
787 | return -ENOTEMPTY; | 787 | return -ENOTEMPTY; |
788 | } | 788 | } |
789 | } | 789 | } |
790 | up(&victim_f->sem); | 790 | mutex_unlock(&victim_f->sem); |
791 | } | 791 | } |
792 | } | 792 | } |
793 | 793 | ||
@@ -816,9 +816,9 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | |||
816 | /* Don't oops if the victim was a dirent pointing to an | 816 | /* Don't oops if the victim was a dirent pointing to an |
817 | inode which didn't exist. */ | 817 | inode which didn't exist. */ |
818 | if (victim_f->inocache) { | 818 | if (victim_f->inocache) { |
819 | down(&victim_f->sem); | 819 | mutex_lock(&victim_f->sem); |
820 | victim_f->inocache->nlink--; | 820 | victim_f->inocache->nlink--; |
821 | up(&victim_f->sem); | 821 | mutex_unlock(&victim_f->sem); |
822 | } | 822 | } |
823 | } | 823 | } |
824 | 824 | ||
@@ -836,11 +836,11 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, | |||
836 | if (ret) { | 836 | if (ret) { |
837 | /* Oh shit. We really ought to make a single node which can do both atomically */ | 837 | /* Oh shit. We really ought to make a single node which can do both atomically */ |
838 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); | 838 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); |
839 | down(&f->sem); | 839 | mutex_lock(&f->sem); |
840 | inc_nlink(old_dentry->d_inode); | 840 | inc_nlink(old_dentry->d_inode); |
841 | if (f->inocache) | 841 | if (f->inocache) |
842 | f->inocache->nlink++; | 842 | f->inocache->nlink++; |
843 | up(&f->sem); | 843 | mutex_unlock(&f->sem); |
844 | 844 | ||
845 | printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); | 845 | printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); |
846 | /* Might as well let the VFS know */ | 846 | /* Might as well let the VFS know */ |
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index a1db9180633f..25a640e566d3 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
@@ -50,14 +50,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
50 | instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); | 50 | instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); |
51 | if (!instr) { | 51 | if (!instr) { |
52 | printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); | 52 | printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); |
53 | down(&c->erase_free_sem); | 53 | mutex_lock(&c->erase_free_sem); |
54 | spin_lock(&c->erase_completion_lock); | 54 | spin_lock(&c->erase_completion_lock); |
55 | list_move(&jeb->list, &c->erase_pending_list); | 55 | list_move(&jeb->list, &c->erase_pending_list); |
56 | c->erasing_size -= c->sector_size; | 56 | c->erasing_size -= c->sector_size; |
57 | c->dirty_size += c->sector_size; | 57 | c->dirty_size += c->sector_size; |
58 | jeb->dirty_size = c->sector_size; | 58 | jeb->dirty_size = c->sector_size; |
59 | spin_unlock(&c->erase_completion_lock); | 59 | spin_unlock(&c->erase_completion_lock); |
60 | up(&c->erase_free_sem); | 60 | mutex_unlock(&c->erase_free_sem); |
61 | return; | 61 | return; |
62 | } | 62 | } |
63 | 63 | ||
@@ -84,14 +84,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, | |||
84 | if (ret == -ENOMEM || ret == -EAGAIN) { | 84 | if (ret == -ENOMEM || ret == -EAGAIN) { |
85 | /* Erase failed immediately. Refile it on the list */ | 85 | /* Erase failed immediately. Refile it on the list */ |
86 | D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); | 86 | D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); |
87 | down(&c->erase_free_sem); | 87 | mutex_lock(&c->erase_free_sem); |
88 | spin_lock(&c->erase_completion_lock); | 88 | spin_lock(&c->erase_completion_lock); |
89 | list_move(&jeb->list, &c->erase_pending_list); | 89 | list_move(&jeb->list, &c->erase_pending_list); |
90 | c->erasing_size -= c->sector_size; | 90 | c->erasing_size -= c->sector_size; |
91 | c->dirty_size += c->sector_size; | 91 | c->dirty_size += c->sector_size; |
92 | jeb->dirty_size = c->sector_size; | 92 | jeb->dirty_size = c->sector_size; |
93 | spin_unlock(&c->erase_completion_lock); | 93 | spin_unlock(&c->erase_completion_lock); |
94 | up(&c->erase_free_sem); | 94 | mutex_unlock(&c->erase_free_sem); |
95 | return; | 95 | return; |
96 | } | 96 | } |
97 | 97 | ||
@@ -107,7 +107,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
107 | { | 107 | { |
108 | struct jffs2_eraseblock *jeb; | 108 | struct jffs2_eraseblock *jeb; |
109 | 109 | ||
110 | down(&c->erase_free_sem); | 110 | mutex_lock(&c->erase_free_sem); |
111 | 111 | ||
112 | spin_lock(&c->erase_completion_lock); | 112 | spin_lock(&c->erase_completion_lock); |
113 | 113 | ||
@@ -116,9 +116,9 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
116 | 116 | ||
117 | if (!list_empty(&c->erase_complete_list)) { | 117 | if (!list_empty(&c->erase_complete_list)) { |
118 | jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); | 118 | jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); |
119 | list_del(&jeb->list); | 119 | list_move(&jeb->list, &c->erase_checking_list); |
120 | spin_unlock(&c->erase_completion_lock); | 120 | spin_unlock(&c->erase_completion_lock); |
121 | up(&c->erase_free_sem); | 121 | mutex_unlock(&c->erase_free_sem); |
122 | jffs2_mark_erased_block(c, jeb); | 122 | jffs2_mark_erased_block(c, jeb); |
123 | 123 | ||
124 | if (!--count) { | 124 | if (!--count) { |
@@ -139,7 +139,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
139 | jffs2_free_jeb_node_refs(c, jeb); | 139 | jffs2_free_jeb_node_refs(c, jeb); |
140 | list_add(&jeb->list, &c->erasing_list); | 140 | list_add(&jeb->list, &c->erasing_list); |
141 | spin_unlock(&c->erase_completion_lock); | 141 | spin_unlock(&c->erase_completion_lock); |
142 | up(&c->erase_free_sem); | 142 | mutex_unlock(&c->erase_free_sem); |
143 | 143 | ||
144 | jffs2_erase_block(c, jeb); | 144 | jffs2_erase_block(c, jeb); |
145 | 145 | ||
@@ -149,12 +149,12 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
149 | 149 | ||
150 | /* Be nice */ | 150 | /* Be nice */ |
151 | yield(); | 151 | yield(); |
152 | down(&c->erase_free_sem); | 152 | mutex_lock(&c->erase_free_sem); |
153 | spin_lock(&c->erase_completion_lock); | 153 | spin_lock(&c->erase_completion_lock); |
154 | } | 154 | } |
155 | 155 | ||
156 | spin_unlock(&c->erase_completion_lock); | 156 | spin_unlock(&c->erase_completion_lock); |
157 | up(&c->erase_free_sem); | 157 | mutex_unlock(&c->erase_free_sem); |
158 | done: | 158 | done: |
159 | D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); | 159 | D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); |
160 | } | 160 | } |
@@ -162,11 +162,11 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) | |||
162 | static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) | 162 | static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) |
163 | { | 163 | { |
164 | D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset)); | 164 | D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset)); |
165 | down(&c->erase_free_sem); | 165 | mutex_lock(&c->erase_free_sem); |
166 | spin_lock(&c->erase_completion_lock); | 166 | spin_lock(&c->erase_completion_lock); |
167 | list_move_tail(&jeb->list, &c->erase_complete_list); | 167 | list_move_tail(&jeb->list, &c->erase_complete_list); |
168 | spin_unlock(&c->erase_completion_lock); | 168 | spin_unlock(&c->erase_completion_lock); |
169 | up(&c->erase_free_sem); | 169 | mutex_unlock(&c->erase_free_sem); |
170 | /* Ensure that kupdated calls us again to mark them clean */ | 170 | /* Ensure that kupdated calls us again to mark them clean */ |
171 | jffs2_erase_pending_trigger(c); | 171 | jffs2_erase_pending_trigger(c); |
172 | } | 172 | } |
@@ -180,26 +180,26 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
180 | failed too many times. */ | 180 | failed too many times. */ |
181 | if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { | 181 | if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { |
182 | /* We'd like to give this block another try. */ | 182 | /* We'd like to give this block another try. */ |
183 | down(&c->erase_free_sem); | 183 | mutex_lock(&c->erase_free_sem); |
184 | spin_lock(&c->erase_completion_lock); | 184 | spin_lock(&c->erase_completion_lock); |
185 | list_move(&jeb->list, &c->erase_pending_list); | 185 | list_move(&jeb->list, &c->erase_pending_list); |
186 | c->erasing_size -= c->sector_size; | 186 | c->erasing_size -= c->sector_size; |
187 | c->dirty_size += c->sector_size; | 187 | c->dirty_size += c->sector_size; |
188 | jeb->dirty_size = c->sector_size; | 188 | jeb->dirty_size = c->sector_size; |
189 | spin_unlock(&c->erase_completion_lock); | 189 | spin_unlock(&c->erase_completion_lock); |
190 | up(&c->erase_free_sem); | 190 | mutex_unlock(&c->erase_free_sem); |
191 | return; | 191 | return; |
192 | } | 192 | } |
193 | } | 193 | } |
194 | 194 | ||
195 | down(&c->erase_free_sem); | 195 | mutex_lock(&c->erase_free_sem); |
196 | spin_lock(&c->erase_completion_lock); | 196 | spin_lock(&c->erase_completion_lock); |
197 | c->erasing_size -= c->sector_size; | 197 | c->erasing_size -= c->sector_size; |
198 | c->bad_size += c->sector_size; | 198 | c->bad_size += c->sector_size; |
199 | list_move(&jeb->list, &c->bad_list); | 199 | list_move(&jeb->list, &c->bad_list); |
200 | c->nr_erasing_blocks--; | 200 | c->nr_erasing_blocks--; |
201 | spin_unlock(&c->erase_completion_lock); | 201 | spin_unlock(&c->erase_completion_lock); |
202 | up(&c->erase_free_sem); | 202 | mutex_unlock(&c->erase_free_sem); |
203 | wake_up(&c->erase_wait); | 203 | wake_up(&c->erase_wait); |
204 | } | 204 | } |
205 | 205 | ||
@@ -350,9 +350,11 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
350 | break; | 350 | break; |
351 | } while(--retlen); | 351 | } while(--retlen); |
352 | c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size); | 352 | c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size); |
353 | if (retlen) | 353 | if (retlen) { |
354 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n", | 354 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n", |
355 | *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf)); | 355 | *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf)); |
356 | return -EIO; | ||
357 | } | ||
356 | return 0; | 358 | return 0; |
357 | } | 359 | } |
358 | do_flash_read: | 360 | do_flash_read: |
@@ -373,10 +375,12 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
373 | ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf); | 375 | ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf); |
374 | if (ret) { | 376 | if (ret) { |
375 | printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); | 377 | printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); |
378 | ret = -EIO; | ||
376 | goto fail; | 379 | goto fail; |
377 | } | 380 | } |
378 | if (retlen != readlen) { | 381 | if (retlen != readlen) { |
379 | printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen); | 382 | printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen); |
383 | ret = -EIO; | ||
380 | goto fail; | 384 | goto fail; |
381 | } | 385 | } |
382 | for (i=0; i<readlen; i += sizeof(unsigned long)) { | 386 | for (i=0; i<readlen; i += sizeof(unsigned long)) { |
@@ -385,6 +389,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
385 | if (*datum + 1) { | 389 | if (*datum + 1) { |
386 | *bad_offset += i; | 390 | *bad_offset += i; |
387 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", *datum, *bad_offset); | 391 | printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", *datum, *bad_offset); |
392 | ret = -EIO; | ||
388 | goto fail; | 393 | goto fail; |
389 | } | 394 | } |
390 | } | 395 | } |
@@ -419,9 +424,6 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
419 | if (jffs2_write_nand_cleanmarker(c, jeb)) | 424 | if (jffs2_write_nand_cleanmarker(c, jeb)) |
420 | goto filebad; | 425 | goto filebad; |
421 | } | 426 | } |
422 | |||
423 | /* Everything else got zeroed before the erase */ | ||
424 | jeb->free_size = c->sector_size; | ||
425 | } else { | 427 | } else { |
426 | 428 | ||
427 | struct kvec vecs[1]; | 429 | struct kvec vecs[1]; |
@@ -449,48 +451,50 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb | |||
449 | 451 | ||
450 | goto filebad; | 452 | goto filebad; |
451 | } | 453 | } |
452 | |||
453 | /* Everything else got zeroed before the erase */ | ||
454 | jeb->free_size = c->sector_size; | ||
455 | /* FIXME Special case for cleanmarker in empty block */ | ||
456 | jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL); | ||
457 | } | 454 | } |
455 | /* Everything else got zeroed before the erase */ | ||
456 | jeb->free_size = c->sector_size; | ||
458 | 457 | ||
459 | down(&c->erase_free_sem); | 458 | mutex_lock(&c->erase_free_sem); |
460 | spin_lock(&c->erase_completion_lock); | 459 | spin_lock(&c->erase_completion_lock); |
460 | |||
461 | c->erasing_size -= c->sector_size; | 461 | c->erasing_size -= c->sector_size; |
462 | c->free_size += jeb->free_size; | 462 | c->free_size += c->sector_size; |
463 | c->used_size += jeb->used_size; | ||
464 | 463 | ||
465 | jffs2_dbg_acct_sanity_check_nolock(c,jeb); | 464 | /* Account for cleanmarker now, if it's in-band */ |
466 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); | 465 | if (c->cleanmarker_size && !jffs2_cleanmarker_oob(c)) |
466 | jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL); | ||
467 | 467 | ||
468 | list_add_tail(&jeb->list, &c->free_list); | 468 | list_move_tail(&jeb->list, &c->free_list); |
469 | c->nr_erasing_blocks--; | 469 | c->nr_erasing_blocks--; |
470 | c->nr_free_blocks++; | 470 | c->nr_free_blocks++; |
471 | |||
472 | jffs2_dbg_acct_sanity_check_nolock(c, jeb); | ||
473 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); | ||
474 | |||
471 | spin_unlock(&c->erase_completion_lock); | 475 | spin_unlock(&c->erase_completion_lock); |
472 | up(&c->erase_free_sem); | 476 | mutex_unlock(&c->erase_free_sem); |
473 | wake_up(&c->erase_wait); | 477 | wake_up(&c->erase_wait); |
474 | return; | 478 | return; |
475 | 479 | ||
476 | filebad: | 480 | filebad: |
477 | down(&c->erase_free_sem); | 481 | mutex_lock(&c->erase_free_sem); |
478 | spin_lock(&c->erase_completion_lock); | 482 | spin_lock(&c->erase_completion_lock); |
479 | /* Stick it on a list (any list) so erase_failed can take it | 483 | /* Stick it on a list (any list) so erase_failed can take it |
480 | right off again. Silly, but shouldn't happen often. */ | 484 | right off again. Silly, but shouldn't happen often. */ |
481 | list_add(&jeb->list, &c->erasing_list); | 485 | list_move(&jeb->list, &c->erasing_list); |
482 | spin_unlock(&c->erase_completion_lock); | 486 | spin_unlock(&c->erase_completion_lock); |
483 | up(&c->erase_free_sem); | 487 | mutex_unlock(&c->erase_free_sem); |
484 | jffs2_erase_failed(c, jeb, bad_offset); | 488 | jffs2_erase_failed(c, jeb, bad_offset); |
485 | return; | 489 | return; |
486 | 490 | ||
487 | refile: | 491 | refile: |
488 | /* Stick it back on the list from whence it came and come back later */ | 492 | /* Stick it back on the list from whence it came and come back later */ |
489 | jffs2_erase_pending_trigger(c); | 493 | jffs2_erase_pending_trigger(c); |
490 | down(&c->erase_free_sem); | 494 | mutex_lock(&c->erase_free_sem); |
491 | spin_lock(&c->erase_completion_lock); | 495 | spin_lock(&c->erase_completion_lock); |
492 | list_add(&jeb->list, &c->erase_complete_list); | 496 | list_move(&jeb->list, &c->erase_complete_list); |
493 | spin_unlock(&c->erase_completion_lock); | 497 | spin_unlock(&c->erase_completion_lock); |
494 | up(&c->erase_free_sem); | 498 | mutex_unlock(&c->erase_free_sem); |
495 | return; | 499 | return; |
496 | } | 500 | } |
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index dcc2734e0b5d..5e920343b2c5 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c | |||
@@ -115,9 +115,9 @@ static int jffs2_readpage (struct file *filp, struct page *pg) | |||
115 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host); | 115 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host); |
116 | int ret; | 116 | int ret; |
117 | 117 | ||
118 | down(&f->sem); | 118 | mutex_lock(&f->sem); |
119 | ret = jffs2_do_readpage_unlock(pg->mapping->host, pg); | 119 | ret = jffs2_do_readpage_unlock(pg->mapping->host, pg); |
120 | up(&f->sem); | 120 | mutex_unlock(&f->sem); |
121 | return ret; | 121 | return ret; |
122 | } | 122 | } |
123 | 123 | ||
@@ -154,7 +154,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, | |||
154 | if (ret) | 154 | if (ret) |
155 | goto out_page; | 155 | goto out_page; |
156 | 156 | ||
157 | down(&f->sem); | 157 | mutex_lock(&f->sem); |
158 | memset(&ri, 0, sizeof(ri)); | 158 | memset(&ri, 0, sizeof(ri)); |
159 | 159 | ||
160 | ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 160 | ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
@@ -181,7 +181,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, | |||
181 | if (IS_ERR(fn)) { | 181 | if (IS_ERR(fn)) { |
182 | ret = PTR_ERR(fn); | 182 | ret = PTR_ERR(fn); |
183 | jffs2_complete_reservation(c); | 183 | jffs2_complete_reservation(c); |
184 | up(&f->sem); | 184 | mutex_unlock(&f->sem); |
185 | goto out_page; | 185 | goto out_page; |
186 | } | 186 | } |
187 | ret = jffs2_add_full_dnode_to_inode(c, f, fn); | 187 | ret = jffs2_add_full_dnode_to_inode(c, f, fn); |
@@ -195,12 +195,12 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, | |||
195 | jffs2_mark_node_obsolete(c, fn->raw); | 195 | jffs2_mark_node_obsolete(c, fn->raw); |
196 | jffs2_free_full_dnode(fn); | 196 | jffs2_free_full_dnode(fn); |
197 | jffs2_complete_reservation(c); | 197 | jffs2_complete_reservation(c); |
198 | up(&f->sem); | 198 | mutex_unlock(&f->sem); |
199 | goto out_page; | 199 | goto out_page; |
200 | } | 200 | } |
201 | jffs2_complete_reservation(c); | 201 | jffs2_complete_reservation(c); |
202 | inode->i_size = pageofs; | 202 | inode->i_size = pageofs; |
203 | up(&f->sem); | 203 | mutex_unlock(&f->sem); |
204 | } | 204 | } |
205 | 205 | ||
206 | /* | 206 | /* |
@@ -209,9 +209,9 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, | |||
209 | * case of a short-copy. | 209 | * case of a short-copy. |
210 | */ | 210 | */ |
211 | if (!PageUptodate(pg)) { | 211 | if (!PageUptodate(pg)) { |
212 | down(&f->sem); | 212 | mutex_lock(&f->sem); |
213 | ret = jffs2_do_readpage_nolock(inode, pg); | 213 | ret = jffs2_do_readpage_nolock(inode, pg); |
214 | up(&f->sem); | 214 | mutex_unlock(&f->sem); |
215 | if (ret) | 215 | if (ret) |
216 | goto out_page; | 216 | goto out_page; |
217 | } | 217 | } |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index e26ea78c7892..3eb1c84b0a33 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
@@ -36,6 +36,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
36 | unsigned int ivalid; | 36 | unsigned int ivalid; |
37 | uint32_t alloclen; | 37 | uint32_t alloclen; |
38 | int ret; | 38 | int ret; |
39 | int alloc_type = ALLOC_NORMAL; | ||
39 | 40 | ||
40 | D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); | 41 | D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); |
41 | 42 | ||
@@ -50,20 +51,20 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
50 | mdata = (char *)&dev; | 51 | mdata = (char *)&dev; |
51 | D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen)); | 52 | D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen)); |
52 | } else if (S_ISLNK(inode->i_mode)) { | 53 | } else if (S_ISLNK(inode->i_mode)) { |
53 | down(&f->sem); | 54 | mutex_lock(&f->sem); |
54 | mdatalen = f->metadata->size; | 55 | mdatalen = f->metadata->size; |
55 | mdata = kmalloc(f->metadata->size, GFP_USER); | 56 | mdata = kmalloc(f->metadata->size, GFP_USER); |
56 | if (!mdata) { | 57 | if (!mdata) { |
57 | up(&f->sem); | 58 | mutex_unlock(&f->sem); |
58 | return -ENOMEM; | 59 | return -ENOMEM; |
59 | } | 60 | } |
60 | ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen); | 61 | ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen); |
61 | if (ret) { | 62 | if (ret) { |
62 | up(&f->sem); | 63 | mutex_unlock(&f->sem); |
63 | kfree(mdata); | 64 | kfree(mdata); |
64 | return ret; | 65 | return ret; |
65 | } | 66 | } |
66 | up(&f->sem); | 67 | mutex_unlock(&f->sem); |
67 | D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen)); | 68 | D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen)); |
68 | } | 69 | } |
69 | 70 | ||
@@ -82,7 +83,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
82 | kfree(mdata); | 83 | kfree(mdata); |
83 | return ret; | 84 | return ret; |
84 | } | 85 | } |
85 | down(&f->sem); | 86 | mutex_lock(&f->sem); |
86 | ivalid = iattr->ia_valid; | 87 | ivalid = iattr->ia_valid; |
87 | 88 | ||
88 | ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 89 | ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
@@ -115,6 +116,10 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
115 | ri->compr = JFFS2_COMPR_ZERO; | 116 | ri->compr = JFFS2_COMPR_ZERO; |
116 | ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size); | 117 | ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size); |
117 | ri->offset = cpu_to_je32(inode->i_size); | 118 | ri->offset = cpu_to_je32(inode->i_size); |
119 | } else if (ivalid & ATTR_SIZE && !iattr->ia_size) { | ||
120 | /* For truncate-to-zero, treat it as deletion because | ||
121 | it'll always be obsoleting all previous nodes */ | ||
122 | alloc_type = ALLOC_DELETION; | ||
118 | } | 123 | } |
119 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); | 124 | ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); |
120 | if (mdatalen) | 125 | if (mdatalen) |
@@ -122,14 +127,14 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
122 | else | 127 | else |
123 | ri->data_crc = cpu_to_je32(0); | 128 | ri->data_crc = cpu_to_je32(0); |
124 | 129 | ||
125 | new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, ALLOC_NORMAL); | 130 | new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, alloc_type); |
126 | if (S_ISLNK(inode->i_mode)) | 131 | if (S_ISLNK(inode->i_mode)) |
127 | kfree(mdata); | 132 | kfree(mdata); |
128 | 133 | ||
129 | if (IS_ERR(new_metadata)) { | 134 | if (IS_ERR(new_metadata)) { |
130 | jffs2_complete_reservation(c); | 135 | jffs2_complete_reservation(c); |
131 | jffs2_free_raw_inode(ri); | 136 | jffs2_free_raw_inode(ri); |
132 | up(&f->sem); | 137 | mutex_unlock(&f->sem); |
133 | return PTR_ERR(new_metadata); | 138 | return PTR_ERR(new_metadata); |
134 | } | 139 | } |
135 | /* It worked. Update the inode */ | 140 | /* It worked. Update the inode */ |
@@ -149,6 +154,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
149 | if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { | 154 | if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { |
150 | jffs2_add_full_dnode_to_inode(c, f, new_metadata); | 155 | jffs2_add_full_dnode_to_inode(c, f, new_metadata); |
151 | inode->i_size = iattr->ia_size; | 156 | inode->i_size = iattr->ia_size; |
157 | inode->i_blocks = (inode->i_size + 511) >> 9; | ||
152 | f->metadata = NULL; | 158 | f->metadata = NULL; |
153 | } else { | 159 | } else { |
154 | f->metadata = new_metadata; | 160 | f->metadata = new_metadata; |
@@ -159,7 +165,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
159 | } | 165 | } |
160 | jffs2_free_raw_inode(ri); | 166 | jffs2_free_raw_inode(ri); |
161 | 167 | ||
162 | up(&f->sem); | 168 | mutex_unlock(&f->sem); |
163 | jffs2_complete_reservation(c); | 169 | jffs2_complete_reservation(c); |
164 | 170 | ||
165 | /* We have to do the vmtruncate() without f->sem held, since | 171 | /* We have to do the vmtruncate() without f->sem held, since |
@@ -167,8 +173,10 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
167 | We are protected from a simultaneous write() extending i_size | 173 | We are protected from a simultaneous write() extending i_size |
168 | back past iattr->ia_size, because do_truncate() holds the | 174 | back past iattr->ia_size, because do_truncate() holds the |
169 | generic inode semaphore. */ | 175 | generic inode semaphore. */ |
170 | if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) | 176 | if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) { |
171 | vmtruncate(inode, iattr->ia_size); | 177 | vmtruncate(inode, iattr->ia_size); |
178 | inode->i_blocks = (inode->i_size + 511) >> 9; | ||
179 | } | ||
172 | 180 | ||
173 | return 0; | 181 | return 0; |
174 | } | 182 | } |
@@ -248,12 +256,12 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino) | |||
248 | c = JFFS2_SB_INFO(inode->i_sb); | 256 | c = JFFS2_SB_INFO(inode->i_sb); |
249 | 257 | ||
250 | jffs2_init_inode_info(f); | 258 | jffs2_init_inode_info(f); |
251 | down(&f->sem); | 259 | mutex_lock(&f->sem); |
252 | 260 | ||
253 | ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); | 261 | ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); |
254 | 262 | ||
255 | if (ret) { | 263 | if (ret) { |
256 | up(&f->sem); | 264 | mutex_unlock(&f->sem); |
257 | iget_failed(inode); | 265 | iget_failed(inode); |
258 | return ERR_PTR(ret); | 266 | return ERR_PTR(ret); |
259 | } | 267 | } |
@@ -330,7 +338,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino) | |||
330 | printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu\n", inode->i_mode, (unsigned long)inode->i_ino); | 338 | printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu\n", inode->i_mode, (unsigned long)inode->i_ino); |
331 | } | 339 | } |
332 | 340 | ||
333 | up(&f->sem); | 341 | mutex_unlock(&f->sem); |
334 | 342 | ||
335 | D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n")); | 343 | D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n")); |
336 | unlock_new_inode(inode); | 344 | unlock_new_inode(inode); |
@@ -339,7 +347,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino) | |||
339 | error_io: | 347 | error_io: |
340 | ret = -EIO; | 348 | ret = -EIO; |
341 | error: | 349 | error: |
342 | up(&f->sem); | 350 | mutex_unlock(&f->sem); |
343 | jffs2_do_clear_inode(c, f); | 351 | jffs2_do_clear_inode(c, f); |
344 | iget_failed(inode); | 352 | iget_failed(inode); |
345 | return ERR_PTR(ret); | 353 | return ERR_PTR(ret); |
@@ -380,9 +388,9 @@ int jffs2_remount_fs (struct super_block *sb, int *flags, char *data) | |||
380 | Flush the writebuffer, if neccecary, else we loose it */ | 388 | Flush the writebuffer, if neccecary, else we loose it */ |
381 | if (!(sb->s_flags & MS_RDONLY)) { | 389 | if (!(sb->s_flags & MS_RDONLY)) { |
382 | jffs2_stop_garbage_collect_thread(c); | 390 | jffs2_stop_garbage_collect_thread(c); |
383 | down(&c->alloc_sem); | 391 | mutex_lock(&c->alloc_sem); |
384 | jffs2_flush_wbuf_pad(c); | 392 | jffs2_flush_wbuf_pad(c); |
385 | up(&c->alloc_sem); | 393 | mutex_unlock(&c->alloc_sem); |
386 | } | 394 | } |
387 | 395 | ||
388 | if (!(*flags & MS_RDONLY)) | 396 | if (!(*flags & MS_RDONLY)) |
@@ -429,7 +437,7 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i | |||
429 | 437 | ||
430 | f = JFFS2_INODE_INFO(inode); | 438 | f = JFFS2_INODE_INFO(inode); |
431 | jffs2_init_inode_info(f); | 439 | jffs2_init_inode_info(f); |
432 | down(&f->sem); | 440 | mutex_lock(&f->sem); |
433 | 441 | ||
434 | memset(ri, 0, sizeof(*ri)); | 442 | memset(ri, 0, sizeof(*ri)); |
435 | /* Set OS-specific defaults for new inodes */ | 443 | /* Set OS-specific defaults for new inodes */ |
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 32ff0373aa04..bad005664e30 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c | |||
@@ -126,7 +126,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
126 | int ret = 0, inum, nlink; | 126 | int ret = 0, inum, nlink; |
127 | int xattr = 0; | 127 | int xattr = 0; |
128 | 128 | ||
129 | if (down_interruptible(&c->alloc_sem)) | 129 | if (mutex_lock_interruptible(&c->alloc_sem)) |
130 | return -EINTR; | 130 | return -EINTR; |
131 | 131 | ||
132 | for (;;) { | 132 | for (;;) { |
@@ -143,7 +143,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
143 | c->unchecked_size); | 143 | c->unchecked_size); |
144 | jffs2_dbg_dump_block_lists_nolock(c); | 144 | jffs2_dbg_dump_block_lists_nolock(c); |
145 | spin_unlock(&c->erase_completion_lock); | 145 | spin_unlock(&c->erase_completion_lock); |
146 | up(&c->alloc_sem); | 146 | mutex_unlock(&c->alloc_sem); |
147 | return -ENOSPC; | 147 | return -ENOSPC; |
148 | } | 148 | } |
149 | 149 | ||
@@ -190,7 +190,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
190 | made no progress in this case, but that should be OK */ | 190 | made no progress in this case, but that should be OK */ |
191 | c->checked_ino--; | 191 | c->checked_ino--; |
192 | 192 | ||
193 | up(&c->alloc_sem); | 193 | mutex_unlock(&c->alloc_sem); |
194 | sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); | 194 | sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); |
195 | return 0; | 195 | return 0; |
196 | 196 | ||
@@ -210,7 +210,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
210 | printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino); | 210 | printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino); |
211 | 211 | ||
212 | jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); | 212 | jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); |
213 | up(&c->alloc_sem); | 213 | mutex_unlock(&c->alloc_sem); |
214 | return ret; | 214 | return ret; |
215 | } | 215 | } |
216 | 216 | ||
@@ -221,9 +221,15 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
221 | jeb = jffs2_find_gc_block(c); | 221 | jeb = jffs2_find_gc_block(c); |
222 | 222 | ||
223 | if (!jeb) { | 223 | if (!jeb) { |
224 | D1 (printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n")); | 224 | /* Couldn't find a free block. But maybe we can just erase one and make 'progress'? */ |
225 | if (!list_empty(&c->erase_pending_list)) { | ||
226 | spin_unlock(&c->erase_completion_lock); | ||
227 | mutex_unlock(&c->alloc_sem); | ||
228 | return -EAGAIN; | ||
229 | } | ||
230 | D1(printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n")); | ||
225 | spin_unlock(&c->erase_completion_lock); | 231 | spin_unlock(&c->erase_completion_lock); |
226 | up(&c->alloc_sem); | 232 | mutex_unlock(&c->alloc_sem); |
227 | return -EIO; | 233 | return -EIO; |
228 | } | 234 | } |
229 | 235 | ||
@@ -232,7 +238,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
232 | printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size)); | 238 | printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size)); |
233 | 239 | ||
234 | if (!jeb->used_size) { | 240 | if (!jeb->used_size) { |
235 | up(&c->alloc_sem); | 241 | mutex_unlock(&c->alloc_sem); |
236 | goto eraseit; | 242 | goto eraseit; |
237 | } | 243 | } |
238 | 244 | ||
@@ -248,7 +254,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
248 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size); | 254 | jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size); |
249 | jeb->gc_node = raw; | 255 | jeb->gc_node = raw; |
250 | spin_unlock(&c->erase_completion_lock); | 256 | spin_unlock(&c->erase_completion_lock); |
251 | up(&c->alloc_sem); | 257 | mutex_unlock(&c->alloc_sem); |
252 | BUG(); | 258 | BUG(); |
253 | } | 259 | } |
254 | } | 260 | } |
@@ -266,7 +272,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
266 | /* Just mark it obsolete */ | 272 | /* Just mark it obsolete */ |
267 | jffs2_mark_node_obsolete(c, raw); | 273 | jffs2_mark_node_obsolete(c, raw); |
268 | } | 274 | } |
269 | up(&c->alloc_sem); | 275 | mutex_unlock(&c->alloc_sem); |
270 | goto eraseit_lock; | 276 | goto eraseit_lock; |
271 | } | 277 | } |
272 | 278 | ||
@@ -334,7 +340,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
334 | */ | 340 | */ |
335 | printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n", | 341 | printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n", |
336 | ic->ino, ic->state); | 342 | ic->ino, ic->state); |
337 | up(&c->alloc_sem); | 343 | mutex_unlock(&c->alloc_sem); |
338 | spin_unlock(&c->inocache_lock); | 344 | spin_unlock(&c->inocache_lock); |
339 | BUG(); | 345 | BUG(); |
340 | 346 | ||
@@ -345,7 +351,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
345 | the alloc_sem() (for marking nodes invalid) so we must | 351 | the alloc_sem() (for marking nodes invalid) so we must |
346 | drop the alloc_sem before sleeping. */ | 352 | drop the alloc_sem before sleeping. */ |
347 | 353 | ||
348 | up(&c->alloc_sem); | 354 | mutex_unlock(&c->alloc_sem); |
349 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n", | 355 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n", |
350 | ic->ino, ic->state)); | 356 | ic->ino, ic->state)); |
351 | sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); | 357 | sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); |
@@ -416,7 +422,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
416 | ret = -ENOSPC; | 422 | ret = -ENOSPC; |
417 | } | 423 | } |
418 | release_sem: | 424 | release_sem: |
419 | up(&c->alloc_sem); | 425 | mutex_unlock(&c->alloc_sem); |
420 | 426 | ||
421 | eraseit_lock: | 427 | eraseit_lock: |
422 | /* If we've finished this block, start it erasing */ | 428 | /* If we've finished this block, start it erasing */ |
@@ -445,7 +451,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era | |||
445 | uint32_t start = 0, end = 0, nrfrags = 0; | 451 | uint32_t start = 0, end = 0, nrfrags = 0; |
446 | int ret = 0; | 452 | int ret = 0; |
447 | 453 | ||
448 | down(&f->sem); | 454 | mutex_lock(&f->sem); |
449 | 455 | ||
450 | /* Now we have the lock for this inode. Check that it's still the one at the head | 456 | /* Now we have the lock for this inode. Check that it's still the one at the head |
451 | of the list. */ | 457 | of the list. */ |
@@ -525,7 +531,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era | |||
525 | } | 531 | } |
526 | } | 532 | } |
527 | upnout: | 533 | upnout: |
528 | up(&f->sem); | 534 | mutex_unlock(&f->sem); |
529 | 535 | ||
530 | return ret; | 536 | return ret; |
531 | } | 537 | } |
@@ -846,7 +852,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct | |||
846 | /* Prevent the erase code from nicking the obsolete node refs while | 852 | /* Prevent the erase code from nicking the obsolete node refs while |
847 | we're looking at them. I really don't like this extra lock but | 853 | we're looking at them. I really don't like this extra lock but |
848 | can't see any alternative. Suggestions on a postcard to... */ | 854 | can't see any alternative. Suggestions on a postcard to... */ |
849 | down(&c->erase_free_sem); | 855 | mutex_lock(&c->erase_free_sem); |
850 | 856 | ||
851 | for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) { | 857 | for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) { |
852 | 858 | ||
@@ -899,7 +905,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct | |||
899 | /* OK. The name really does match. There really is still an older node on | 905 | /* OK. The name really does match. There really is still an older node on |
900 | the flash which our deletion dirent obsoletes. So we have to write out | 906 | the flash which our deletion dirent obsoletes. So we have to write out |
901 | a new deletion dirent to replace it */ | 907 | a new deletion dirent to replace it */ |
902 | up(&c->erase_free_sem); | 908 | mutex_unlock(&c->erase_free_sem); |
903 | 909 | ||
904 | D1(printk(KERN_DEBUG "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n", | 910 | D1(printk(KERN_DEBUG "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n", |
905 | ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino))); | 911 | ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino))); |
@@ -908,7 +914,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct | |||
908 | return jffs2_garbage_collect_dirent(c, jeb, f, fd); | 914 | return jffs2_garbage_collect_dirent(c, jeb, f, fd); |
909 | } | 915 | } |
910 | 916 | ||
911 | up(&c->erase_free_sem); | 917 | mutex_unlock(&c->erase_free_sem); |
912 | kfree(rd); | 918 | kfree(rd); |
913 | } | 919 | } |
914 | 920 | ||
@@ -1081,7 +1087,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras | |||
1081 | return 0; | 1087 | return 0; |
1082 | } | 1088 | } |
1083 | 1089 | ||
1084 | static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 1090 | static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *orig_jeb, |
1085 | struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, | 1091 | struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, |
1086 | uint32_t start, uint32_t end) | 1092 | uint32_t start, uint32_t end) |
1087 | { | 1093 | { |
diff --git a/fs/jffs2/ioctl.c b/fs/jffs2/ioctl.c index f4d525b0ea53..e2177210f621 100644 --- a/fs/jffs2/ioctl.c +++ b/fs/jffs2/ioctl.c | |||
@@ -10,6 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/fs.h> | 12 | #include <linux/fs.h> |
13 | #include "nodelist.h" | ||
13 | 14 | ||
14 | int jffs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | 15 | int jffs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, |
15 | unsigned long arg) | 16 | unsigned long arg) |
diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h index a841f4973a74..31559f45fdde 100644 --- a/fs/jffs2/jffs2_fs_i.h +++ b/fs/jffs2/jffs2_fs_i.h | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <linux/version.h> | 15 | #include <linux/version.h> |
16 | #include <linux/rbtree.h> | 16 | #include <linux/rbtree.h> |
17 | #include <linux/posix_acl.h> | 17 | #include <linux/posix_acl.h> |
18 | #include <linux/semaphore.h> | 18 | #include <linux/mutex.h> |
19 | 19 | ||
20 | struct jffs2_inode_info { | 20 | struct jffs2_inode_info { |
21 | /* We need an internal mutex similar to inode->i_mutex. | 21 | /* We need an internal mutex similar to inode->i_mutex. |
@@ -24,7 +24,7 @@ struct jffs2_inode_info { | |||
24 | before letting GC proceed. Or we'd have to put ugliness | 24 | before letting GC proceed. Or we'd have to put ugliness |
25 | into the GC code so it didn't attempt to obtain the i_mutex | 25 | into the GC code so it didn't attempt to obtain the i_mutex |
26 | for the inode(s) which are already locked */ | 26 | for the inode(s) which are already locked */ |
27 | struct semaphore sem; | 27 | struct mutex sem; |
28 | 28 | ||
29 | /* The highest (datanode) version number used for this ino */ | 29 | /* The highest (datanode) version number used for this ino */ |
30 | uint32_t highest_version; | 30 | uint32_t highest_version; |
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 18fca2b9e531..85ef6dbb1be7 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h | |||
@@ -16,7 +16,7 @@ | |||
16 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
17 | #include <linux/workqueue.h> | 17 | #include <linux/workqueue.h> |
18 | #include <linux/completion.h> | 18 | #include <linux/completion.h> |
19 | #include <linux/semaphore.h> | 19 | #include <linux/mutex.h> |
20 | #include <linux/timer.h> | 20 | #include <linux/timer.h> |
21 | #include <linux/wait.h> | 21 | #include <linux/wait.h> |
22 | #include <linux/list.h> | 22 | #include <linux/list.h> |
@@ -44,7 +44,7 @@ struct jffs2_sb_info { | |||
44 | struct completion gc_thread_start; /* GC thread start completion */ | 44 | struct completion gc_thread_start; /* GC thread start completion */ |
45 | struct completion gc_thread_exit; /* GC thread exit completion port */ | 45 | struct completion gc_thread_exit; /* GC thread exit completion port */ |
46 | 46 | ||
47 | struct semaphore alloc_sem; /* Used to protect all the following | 47 | struct mutex alloc_sem; /* Used to protect all the following |
48 | fields, and also to protect against | 48 | fields, and also to protect against |
49 | out-of-order writing of nodes. And GC. */ | 49 | out-of-order writing of nodes. And GC. */ |
50 | uint32_t cleanmarker_size; /* Size of an _inline_ CLEANMARKER | 50 | uint32_t cleanmarker_size; /* Size of an _inline_ CLEANMARKER |
@@ -87,6 +87,7 @@ struct jffs2_sb_info { | |||
87 | struct list_head erasable_list; /* Blocks which are completely dirty, and need erasing */ | 87 | struct list_head erasable_list; /* Blocks which are completely dirty, and need erasing */ |
88 | struct list_head erasable_pending_wbuf_list; /* Blocks which need erasing but only after the current wbuf is flushed */ | 88 | struct list_head erasable_pending_wbuf_list; /* Blocks which need erasing but only after the current wbuf is flushed */ |
89 | struct list_head erasing_list; /* Blocks which are currently erasing */ | 89 | struct list_head erasing_list; /* Blocks which are currently erasing */ |
90 | struct list_head erase_checking_list; /* Blocks which are being checked and marked */ | ||
90 | struct list_head erase_pending_list; /* Blocks which need erasing now */ | 91 | struct list_head erase_pending_list; /* Blocks which need erasing now */ |
91 | struct list_head erase_complete_list; /* Blocks which are erased and need the clean marker written to them */ | 92 | struct list_head erase_complete_list; /* Blocks which are erased and need the clean marker written to them */ |
92 | struct list_head free_list; /* Blocks which are free and ready to be used */ | 93 | struct list_head free_list; /* Blocks which are free and ready to be used */ |
@@ -104,7 +105,7 @@ struct jffs2_sb_info { | |||
104 | /* Sem to allow jffs2_garbage_collect_deletion_dirent to | 105 | /* Sem to allow jffs2_garbage_collect_deletion_dirent to |
105 | drop the erase_completion_lock while it's holding a pointer | 106 | drop the erase_completion_lock while it's holding a pointer |
106 | to an obsoleted node. I don't like this. Alternatives welcomed. */ | 107 | to an obsoleted node. I don't like this. Alternatives welcomed. */ |
107 | struct semaphore erase_free_sem; | 108 | struct mutex erase_free_sem; |
108 | 109 | ||
109 | uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ | 110 | uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ |
110 | 111 | ||
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index ec1aae9e695e..8219df6eb6d8 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h | |||
@@ -87,7 +87,7 @@ struct jffs2_raw_node_ref | |||
87 | xattr_ref or xattr_datum instead. The common part of those structures | 87 | xattr_ref or xattr_datum instead. The common part of those structures |
88 | has NULL in the first word. See jffs2_raw_ref_to_ic() below */ | 88 | has NULL in the first word. See jffs2_raw_ref_to_ic() below */ |
89 | uint32_t flash_offset; | 89 | uint32_t flash_offset; |
90 | #define TEST_TOTLEN | 90 | #undef TEST_TOTLEN |
91 | #ifdef TEST_TOTLEN | 91 | #ifdef TEST_TOTLEN |
92 | uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */ | 92 | uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */ |
93 | #endif | 93 | #endif |
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index a0313fa8748e..9df8f3ef20df 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c | |||
@@ -48,7 +48,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
48 | minsize = PAD(minsize); | 48 | minsize = PAD(minsize); |
49 | 49 | ||
50 | D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize)); | 50 | D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize)); |
51 | down(&c->alloc_sem); | 51 | mutex_lock(&c->alloc_sem); |
52 | 52 | ||
53 | D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n")); | 53 | D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n")); |
54 | 54 | ||
@@ -57,7 +57,6 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
57 | /* this needs a little more thought (true <tglx> :)) */ | 57 | /* this needs a little more thought (true <tglx> :)) */ |
58 | while(ret == -EAGAIN) { | 58 | while(ret == -EAGAIN) { |
59 | while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { | 59 | while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { |
60 | int ret; | ||
61 | uint32_t dirty, avail; | 60 | uint32_t dirty, avail; |
62 | 61 | ||
63 | /* calculate real dirty size | 62 | /* calculate real dirty size |
@@ -82,7 +81,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
82 | dirty, c->unchecked_size, c->sector_size)); | 81 | dirty, c->unchecked_size, c->sector_size)); |
83 | 82 | ||
84 | spin_unlock(&c->erase_completion_lock); | 83 | spin_unlock(&c->erase_completion_lock); |
85 | up(&c->alloc_sem); | 84 | mutex_unlock(&c->alloc_sem); |
86 | return -ENOSPC; | 85 | return -ENOSPC; |
87 | } | 86 | } |
88 | 87 | ||
@@ -105,11 +104,11 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
105 | D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n", | 104 | D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n", |
106 | avail, blocksneeded * c->sector_size)); | 105 | avail, blocksneeded * c->sector_size)); |
107 | spin_unlock(&c->erase_completion_lock); | 106 | spin_unlock(&c->erase_completion_lock); |
108 | up(&c->alloc_sem); | 107 | mutex_unlock(&c->alloc_sem); |
109 | return -ENOSPC; | 108 | return -ENOSPC; |
110 | } | 109 | } |
111 | 110 | ||
112 | up(&c->alloc_sem); | 111 | mutex_unlock(&c->alloc_sem); |
113 | 112 | ||
114 | D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n", | 113 | D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n", |
115 | c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size, | 114 | c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size, |
@@ -117,7 +116,10 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
117 | spin_unlock(&c->erase_completion_lock); | 116 | spin_unlock(&c->erase_completion_lock); |
118 | 117 | ||
119 | ret = jffs2_garbage_collect_pass(c); | 118 | ret = jffs2_garbage_collect_pass(c); |
120 | if (ret) | 119 | |
120 | if (ret == -EAGAIN) | ||
121 | jffs2_erase_pending_blocks(c, 1); | ||
122 | else if (ret) | ||
121 | return ret; | 123 | return ret; |
122 | 124 | ||
123 | cond_resched(); | 125 | cond_resched(); |
@@ -125,7 +127,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
125 | if (signal_pending(current)) | 127 | if (signal_pending(current)) |
126 | return -EINTR; | 128 | return -EINTR; |
127 | 129 | ||
128 | down(&c->alloc_sem); | 130 | mutex_lock(&c->alloc_sem); |
129 | spin_lock(&c->erase_completion_lock); | 131 | spin_lock(&c->erase_completion_lock); |
130 | } | 132 | } |
131 | 133 | ||
@@ -138,7 +140,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, | |||
138 | if (!ret) | 140 | if (!ret) |
139 | ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); | 141 | ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); |
140 | if (ret) | 142 | if (ret) |
141 | up(&c->alloc_sem); | 143 | mutex_unlock(&c->alloc_sem); |
142 | return ret; | 144 | return ret; |
143 | } | 145 | } |
144 | 146 | ||
@@ -463,7 +465,7 @@ void jffs2_complete_reservation(struct jffs2_sb_info *c) | |||
463 | { | 465 | { |
464 | D1(printk(KERN_DEBUG "jffs2_complete_reservation()\n")); | 466 | D1(printk(KERN_DEBUG "jffs2_complete_reservation()\n")); |
465 | jffs2_garbage_collect_trigger(c); | 467 | jffs2_garbage_collect_trigger(c); |
466 | up(&c->alloc_sem); | 468 | mutex_unlock(&c->alloc_sem); |
467 | } | 469 | } |
468 | 470 | ||
469 | static inline int on_list(struct list_head *obj, struct list_head *head) | 471 | static inline int on_list(struct list_head *obj, struct list_head *head) |
@@ -512,7 +514,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
512 | any jffs2_raw_node_refs. So we don't need to stop erases from | 514 | any jffs2_raw_node_refs. So we don't need to stop erases from |
513 | happening, or protect against people holding an obsolete | 515 | happening, or protect against people holding an obsolete |
514 | jffs2_raw_node_ref without the erase_completion_lock. */ | 516 | jffs2_raw_node_ref without the erase_completion_lock. */ |
515 | down(&c->erase_free_sem); | 517 | mutex_lock(&c->erase_free_sem); |
516 | } | 518 | } |
517 | 519 | ||
518 | spin_lock(&c->erase_completion_lock); | 520 | spin_lock(&c->erase_completion_lock); |
@@ -715,7 +717,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
715 | } | 717 | } |
716 | 718 | ||
717 | out_erase_sem: | 719 | out_erase_sem: |
718 | up(&c->erase_free_sem); | 720 | mutex_unlock(&c->erase_free_sem); |
719 | } | 721 | } |
720 | 722 | ||
721 | int jffs2_thread_should_wake(struct jffs2_sb_info *c) | 723 | int jffs2_thread_should_wake(struct jffs2_sb_info *c) |
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index e512a93d6249..4cb4d76de07f 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -825,8 +825,9 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
825 | else // normal case... | 825 | else // normal case... |
826 | tn->fn->size = je32_to_cpu(rd->dsize); | 826 | tn->fn->size = je32_to_cpu(rd->dsize); |
827 | 827 | ||
828 | dbg_readinode("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n", | 828 | dbg_readinode2("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n", |
829 | ref_offset(ref), je32_to_cpu(rd->version), je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize); | 829 | ref_offset(ref), je32_to_cpu(rd->version), |
830 | je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize); | ||
830 | 831 | ||
831 | ret = jffs2_add_tn_to_tree(c, rii, tn); | 832 | ret = jffs2_add_tn_to_tree(c, rii, tn); |
832 | 833 | ||
@@ -836,13 +837,13 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
836 | jffs2_free_tmp_dnode_info(tn); | 837 | jffs2_free_tmp_dnode_info(tn); |
837 | return ret; | 838 | return ret; |
838 | } | 839 | } |
839 | #ifdef JFFS2_DBG_READINODE_MESSAGES | 840 | #ifdef JFFS2_DBG_READINODE2_MESSAGES |
840 | dbg_readinode("After adding ver %d:\n", je32_to_cpu(rd->version)); | 841 | dbg_readinode2("After adding ver %d:\n", je32_to_cpu(rd->version)); |
841 | tn = tn_first(&rii->tn_root); | 842 | tn = tn_first(&rii->tn_root); |
842 | while (tn) { | 843 | while (tn) { |
843 | dbg_readinode("%p: v %d r 0x%x-0x%x ov %d\n", | 844 | dbg_readinode2("%p: v %d r 0x%x-0x%x ov %d\n", |
844 | tn, tn->version, tn->fn->ofs, | 845 | tn, tn->version, tn->fn->ofs, |
845 | tn->fn->ofs+tn->fn->size, tn->overlapped); | 846 | tn->fn->ofs+tn->fn->size, tn->overlapped); |
846 | tn = tn_next(tn); | 847 | tn = tn_next(tn); |
847 | } | 848 | } |
848 | #endif | 849 | #endif |
@@ -1193,7 +1194,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
1193 | JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n", | 1194 | JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n", |
1194 | ret, retlen, sizeof(*latest_node)); | 1195 | ret, retlen, sizeof(*latest_node)); |
1195 | /* FIXME: If this fails, there seems to be a memory leak. Find it. */ | 1196 | /* FIXME: If this fails, there seems to be a memory leak. Find it. */ |
1196 | up(&f->sem); | 1197 | mutex_unlock(&f->sem); |
1197 | jffs2_do_clear_inode(c, f); | 1198 | jffs2_do_clear_inode(c, f); |
1198 | return ret?ret:-EIO; | 1199 | return ret?ret:-EIO; |
1199 | } | 1200 | } |
@@ -1202,7 +1203,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
1202 | if (crc != je32_to_cpu(latest_node->node_crc)) { | 1203 | if (crc != je32_to_cpu(latest_node->node_crc)) { |
1203 | JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n", | 1204 | JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n", |
1204 | f->inocache->ino, ref_offset(rii.latest_ref)); | 1205 | f->inocache->ino, ref_offset(rii.latest_ref)); |
1205 | up(&f->sem); | 1206 | mutex_unlock(&f->sem); |
1206 | jffs2_do_clear_inode(c, f); | 1207 | jffs2_do_clear_inode(c, f); |
1207 | return -EIO; | 1208 | return -EIO; |
1208 | } | 1209 | } |
@@ -1242,7 +1243,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
1242 | f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); | 1243 | f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); |
1243 | if (!f->target) { | 1244 | if (!f->target) { |
1244 | JFFS2_ERROR("can't allocate %d bytes of memory for the symlink target path cache\n", je32_to_cpu(latest_node->csize)); | 1245 | JFFS2_ERROR("can't allocate %d bytes of memory for the symlink target path cache\n", je32_to_cpu(latest_node->csize)); |
1245 | up(&f->sem); | 1246 | mutex_unlock(&f->sem); |
1246 | jffs2_do_clear_inode(c, f); | 1247 | jffs2_do_clear_inode(c, f); |
1247 | return -ENOMEM; | 1248 | return -ENOMEM; |
1248 | } | 1249 | } |
@@ -1255,7 +1256,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
1255 | ret = -EIO; | 1256 | ret = -EIO; |
1256 | kfree(f->target); | 1257 | kfree(f->target); |
1257 | f->target = NULL; | 1258 | f->target = NULL; |
1258 | up(&f->sem); | 1259 | mutex_unlock(&f->sem); |
1259 | jffs2_do_clear_inode(c, f); | 1260 | jffs2_do_clear_inode(c, f); |
1260 | return -ret; | 1261 | return -ret; |
1261 | } | 1262 | } |
@@ -1273,14 +1274,14 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
1273 | if (f->metadata) { | 1274 | if (f->metadata) { |
1274 | JFFS2_ERROR("Argh. Special inode #%u with mode 0%o had metadata node\n", | 1275 | JFFS2_ERROR("Argh. Special inode #%u with mode 0%o had metadata node\n", |
1275 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); | 1276 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); |
1276 | up(&f->sem); | 1277 | mutex_unlock(&f->sem); |
1277 | jffs2_do_clear_inode(c, f); | 1278 | jffs2_do_clear_inode(c, f); |
1278 | return -EIO; | 1279 | return -EIO; |
1279 | } | 1280 | } |
1280 | if (!frag_first(&f->fragtree)) { | 1281 | if (!frag_first(&f->fragtree)) { |
1281 | JFFS2_ERROR("Argh. Special inode #%u with mode 0%o has no fragments\n", | 1282 | JFFS2_ERROR("Argh. Special inode #%u with mode 0%o has no fragments\n", |
1282 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); | 1283 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); |
1283 | up(&f->sem); | 1284 | mutex_unlock(&f->sem); |
1284 | jffs2_do_clear_inode(c, f); | 1285 | jffs2_do_clear_inode(c, f); |
1285 | return -EIO; | 1286 | return -EIO; |
1286 | } | 1287 | } |
@@ -1289,7 +1290,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
1289 | JFFS2_ERROR("Argh. Special inode #%u with mode 0x%x had more than one node\n", | 1290 | JFFS2_ERROR("Argh. Special inode #%u with mode 0x%x had more than one node\n", |
1290 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); | 1291 | f->inocache->ino, jemode_to_cpu(latest_node->mode)); |
1291 | /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ | 1292 | /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ |
1292 | up(&f->sem); | 1293 | mutex_unlock(&f->sem); |
1293 | jffs2_do_clear_inode(c, f); | 1294 | jffs2_do_clear_inode(c, f); |
1294 | return -EIO; | 1295 | return -EIO; |
1295 | } | 1296 | } |
@@ -1379,12 +1380,13 @@ int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *i | |||
1379 | if (!f) | 1380 | if (!f) |
1380 | return -ENOMEM; | 1381 | return -ENOMEM; |
1381 | 1382 | ||
1382 | init_MUTEX_LOCKED(&f->sem); | 1383 | mutex_init(&f->sem); |
1384 | mutex_lock(&f->sem); | ||
1383 | f->inocache = ic; | 1385 | f->inocache = ic; |
1384 | 1386 | ||
1385 | ret = jffs2_do_read_inode_internal(c, f, &n); | 1387 | ret = jffs2_do_read_inode_internal(c, f, &n); |
1386 | if (!ret) { | 1388 | if (!ret) { |
1387 | up(&f->sem); | 1389 | mutex_unlock(&f->sem); |
1388 | jffs2_do_clear_inode(c, f); | 1390 | jffs2_do_clear_inode(c, f); |
1389 | } | 1391 | } |
1390 | kfree (f); | 1392 | kfree (f); |
@@ -1398,7 +1400,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
1398 | 1400 | ||
1399 | jffs2_clear_acl(f); | 1401 | jffs2_clear_acl(f); |
1400 | jffs2_xattr_delete_inode(c, f->inocache); | 1402 | jffs2_xattr_delete_inode(c, f->inocache); |
1401 | down(&f->sem); | 1403 | mutex_lock(&f->sem); |
1402 | deleted = f->inocache && !f->inocache->nlink; | 1404 | deleted = f->inocache && !f->inocache->nlink; |
1403 | 1405 | ||
1404 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) | 1406 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) |
@@ -1430,5 +1432,5 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
1430 | jffs2_del_ino_cache(c, f->inocache); | 1432 | jffs2_del_ino_cache(c, f->inocache); |
1431 | } | 1433 | } |
1432 | 1434 | ||
1433 | up(&f->sem); | 1435 | mutex_unlock(&f->sem); |
1434 | } | 1436 | } |
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 4677355996cc..f3353df178e7 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
@@ -47,7 +47,7 @@ static void jffs2_i_init_once(struct kmem_cache *cachep, void *foo) | |||
47 | { | 47 | { |
48 | struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo; | 48 | struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo; |
49 | 49 | ||
50 | init_MUTEX(&ei->sem); | 50 | mutex_init(&ei->sem); |
51 | inode_init_once(&ei->vfs_inode); | 51 | inode_init_once(&ei->vfs_inode); |
52 | } | 52 | } |
53 | 53 | ||
@@ -55,9 +55,9 @@ static int jffs2_sync_fs(struct super_block *sb, int wait) | |||
55 | { | 55 | { |
56 | struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); | 56 | struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); |
57 | 57 | ||
58 | down(&c->alloc_sem); | 58 | mutex_lock(&c->alloc_sem); |
59 | jffs2_flush_wbuf_pad(c); | 59 | jffs2_flush_wbuf_pad(c); |
60 | up(&c->alloc_sem); | 60 | mutex_unlock(&c->alloc_sem); |
61 | return 0; | 61 | return 0; |
62 | } | 62 | } |
63 | 63 | ||
@@ -95,8 +95,8 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent) | |||
95 | 95 | ||
96 | /* Initialize JFFS2 superblock locks, the further initialization will | 96 | /* Initialize JFFS2 superblock locks, the further initialization will |
97 | * be done later */ | 97 | * be done later */ |
98 | init_MUTEX(&c->alloc_sem); | 98 | mutex_init(&c->alloc_sem); |
99 | init_MUTEX(&c->erase_free_sem); | 99 | mutex_init(&c->erase_free_sem); |
100 | init_waitqueue_head(&c->erase_wait); | 100 | init_waitqueue_head(&c->erase_wait); |
101 | init_waitqueue_head(&c->inocache_wq); | 101 | init_waitqueue_head(&c->inocache_wq); |
102 | spin_lock_init(&c->erase_completion_lock); | 102 | spin_lock_init(&c->erase_completion_lock); |
@@ -125,9 +125,9 @@ static void jffs2_put_super (struct super_block *sb) | |||
125 | 125 | ||
126 | D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); | 126 | D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); |
127 | 127 | ||
128 | down(&c->alloc_sem); | 128 | mutex_lock(&c->alloc_sem); |
129 | jffs2_flush_wbuf_pad(c); | 129 | jffs2_flush_wbuf_pad(c); |
130 | up(&c->alloc_sem); | 130 | mutex_unlock(&c->alloc_sem); |
131 | 131 | ||
132 | jffs2_sum_exit(c); | 132 | jffs2_sum_exit(c); |
133 | 133 | ||
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index d1d4f27464ba..8de52b607678 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
@@ -578,8 +578,8 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
578 | if (!jffs2_is_writebuffered(c)) | 578 | if (!jffs2_is_writebuffered(c)) |
579 | return 0; | 579 | return 0; |
580 | 580 | ||
581 | if (!down_trylock(&c->alloc_sem)) { | 581 | if (mutex_trylock(&c->alloc_sem)) { |
582 | up(&c->alloc_sem); | 582 | mutex_unlock(&c->alloc_sem); |
583 | printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n"); | 583 | printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n"); |
584 | BUG(); | 584 | BUG(); |
585 | } | 585 | } |
@@ -702,10 +702,10 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) | |||
702 | if (!c->wbuf) | 702 | if (!c->wbuf) |
703 | return 0; | 703 | return 0; |
704 | 704 | ||
705 | down(&c->alloc_sem); | 705 | mutex_lock(&c->alloc_sem); |
706 | if (!jffs2_wbuf_pending_for_ino(c, ino)) { | 706 | if (!jffs2_wbuf_pending_for_ino(c, ino)) { |
707 | D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino)); | 707 | D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino)); |
708 | up(&c->alloc_sem); | 708 | mutex_unlock(&c->alloc_sem); |
709 | return 0; | 709 | return 0; |
710 | } | 710 | } |
711 | 711 | ||
@@ -725,14 +725,14 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) | |||
725 | } else while (old_wbuf_len && | 725 | } else while (old_wbuf_len && |
726 | old_wbuf_ofs == c->wbuf_ofs) { | 726 | old_wbuf_ofs == c->wbuf_ofs) { |
727 | 727 | ||
728 | up(&c->alloc_sem); | 728 | mutex_unlock(&c->alloc_sem); |
729 | 729 | ||
730 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() calls gc pass\n")); | 730 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() calls gc pass\n")); |
731 | 731 | ||
732 | ret = jffs2_garbage_collect_pass(c); | 732 | ret = jffs2_garbage_collect_pass(c); |
733 | if (ret) { | 733 | if (ret) { |
734 | /* GC failed. Flush it with padding instead */ | 734 | /* GC failed. Flush it with padding instead */ |
735 | down(&c->alloc_sem); | 735 | mutex_lock(&c->alloc_sem); |
736 | down_write(&c->wbuf_sem); | 736 | down_write(&c->wbuf_sem); |
737 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); | 737 | ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); |
738 | /* retry flushing wbuf in case jffs2_wbuf_recover | 738 | /* retry flushing wbuf in case jffs2_wbuf_recover |
@@ -742,12 +742,12 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) | |||
742 | up_write(&c->wbuf_sem); | 742 | up_write(&c->wbuf_sem); |
743 | break; | 743 | break; |
744 | } | 744 | } |
745 | down(&c->alloc_sem); | 745 | mutex_lock(&c->alloc_sem); |
746 | } | 746 | } |
747 | 747 | ||
748 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() ends...\n")); | 748 | D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() ends...\n")); |
749 | 749 | ||
750 | up(&c->alloc_sem); | 750 | mutex_unlock(&c->alloc_sem); |
751 | return ret; | 751 | return ret; |
752 | } | 752 | } |
753 | 753 | ||
@@ -1236,12 +1236,24 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) { | |||
1236 | if (!c->wbuf) | 1236 | if (!c->wbuf) |
1237 | return -ENOMEM; | 1237 | return -ENOMEM; |
1238 | 1238 | ||
1239 | #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY | ||
1240 | c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL); | ||
1241 | if (!c->wbuf_verify) { | ||
1242 | kfree(c->oobbuf); | ||
1243 | kfree(c->wbuf); | ||
1244 | return -ENOMEM; | ||
1245 | } | ||
1246 | #endif | ||
1247 | |||
1239 | printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size); | 1248 | printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size); |
1240 | 1249 | ||
1241 | return 0; | 1250 | return 0; |
1242 | } | 1251 | } |
1243 | 1252 | ||
1244 | void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { | 1253 | void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { |
1254 | #ifdef CONFIG_JFFS2_FS_WBUF_VERIFY | ||
1255 | kfree(c->wbuf_verify); | ||
1256 | #endif | ||
1245 | kfree(c->wbuf); | 1257 | kfree(c->wbuf); |
1246 | } | 1258 | } |
1247 | 1259 | ||
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 776f13cbf2b5..665fce9797d3 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c | |||
@@ -137,12 +137,12 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 | |||
137 | JFFS2_SUMMARY_INODE_SIZE); | 137 | JFFS2_SUMMARY_INODE_SIZE); |
138 | } else { | 138 | } else { |
139 | /* Locking pain */ | 139 | /* Locking pain */ |
140 | up(&f->sem); | 140 | mutex_unlock(&f->sem); |
141 | jffs2_complete_reservation(c); | 141 | jffs2_complete_reservation(c); |
142 | 142 | ||
143 | ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &dummy, | 143 | ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &dummy, |
144 | alloc_mode, JFFS2_SUMMARY_INODE_SIZE); | 144 | alloc_mode, JFFS2_SUMMARY_INODE_SIZE); |
145 | down(&f->sem); | 145 | mutex_lock(&f->sem); |
146 | } | 146 | } |
147 | 147 | ||
148 | if (!ret) { | 148 | if (!ret) { |
@@ -285,12 +285,12 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff | |||
285 | JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | 285 | JFFS2_SUMMARY_DIRENT_SIZE(namelen)); |
286 | } else { | 286 | } else { |
287 | /* Locking pain */ | 287 | /* Locking pain */ |
288 | up(&f->sem); | 288 | mutex_unlock(&f->sem); |
289 | jffs2_complete_reservation(c); | 289 | jffs2_complete_reservation(c); |
290 | 290 | ||
291 | ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &dummy, | 291 | ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &dummy, |
292 | alloc_mode, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); | 292 | alloc_mode, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); |
293 | down(&f->sem); | 293 | mutex_lock(&f->sem); |
294 | } | 294 | } |
295 | 295 | ||
296 | if (!ret) { | 296 | if (!ret) { |
@@ -353,7 +353,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
353 | D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); | 353 | D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); |
354 | break; | 354 | break; |
355 | } | 355 | } |
356 | down(&f->sem); | 356 | mutex_lock(&f->sem); |
357 | datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1))); | 357 | datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1))); |
358 | cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen); | 358 | cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen); |
359 | 359 | ||
@@ -381,7 +381,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
381 | 381 | ||
382 | if (IS_ERR(fn)) { | 382 | if (IS_ERR(fn)) { |
383 | ret = PTR_ERR(fn); | 383 | ret = PTR_ERR(fn); |
384 | up(&f->sem); | 384 | mutex_unlock(&f->sem); |
385 | jffs2_complete_reservation(c); | 385 | jffs2_complete_reservation(c); |
386 | if (!retried) { | 386 | if (!retried) { |
387 | /* Write error to be retried */ | 387 | /* Write error to be retried */ |
@@ -403,11 +403,11 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
403 | jffs2_mark_node_obsolete(c, fn->raw); | 403 | jffs2_mark_node_obsolete(c, fn->raw); |
404 | jffs2_free_full_dnode(fn); | 404 | jffs2_free_full_dnode(fn); |
405 | 405 | ||
406 | up(&f->sem); | 406 | mutex_unlock(&f->sem); |
407 | jffs2_complete_reservation(c); | 407 | jffs2_complete_reservation(c); |
408 | break; | 408 | break; |
409 | } | 409 | } |
410 | up(&f->sem); | 410 | mutex_unlock(&f->sem); |
411 | jffs2_complete_reservation(c); | 411 | jffs2_complete_reservation(c); |
412 | if (!datalen) { | 412 | if (!datalen) { |
413 | printk(KERN_WARNING "Eep. We didn't actually write any data in jffs2_write_inode_range()\n"); | 413 | printk(KERN_WARNING "Eep. We didn't actually write any data in jffs2_write_inode_range()\n"); |
@@ -439,7 +439,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
439 | JFFS2_SUMMARY_INODE_SIZE); | 439 | JFFS2_SUMMARY_INODE_SIZE); |
440 | D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); | 440 | D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); |
441 | if (ret) { | 441 | if (ret) { |
442 | up(&f->sem); | 442 | mutex_unlock(&f->sem); |
443 | return ret; | 443 | return ret; |
444 | } | 444 | } |
445 | 445 | ||
@@ -454,7 +454,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
454 | if (IS_ERR(fn)) { | 454 | if (IS_ERR(fn)) { |
455 | D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n")); | 455 | D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n")); |
456 | /* Eeek. Wave bye bye */ | 456 | /* Eeek. Wave bye bye */ |
457 | up(&f->sem); | 457 | mutex_unlock(&f->sem); |
458 | jffs2_complete_reservation(c); | 458 | jffs2_complete_reservation(c); |
459 | return PTR_ERR(fn); | 459 | return PTR_ERR(fn); |
460 | } | 460 | } |
@@ -463,7 +463,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
463 | */ | 463 | */ |
464 | f->metadata = fn; | 464 | f->metadata = fn; |
465 | 465 | ||
466 | up(&f->sem); | 466 | mutex_unlock(&f->sem); |
467 | jffs2_complete_reservation(c); | 467 | jffs2_complete_reservation(c); |
468 | 468 | ||
469 | ret = jffs2_init_security(&f->vfs_inode, &dir_f->vfs_inode); | 469 | ret = jffs2_init_security(&f->vfs_inode, &dir_f->vfs_inode); |
@@ -489,7 +489,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
489 | return -ENOMEM; | 489 | return -ENOMEM; |
490 | } | 490 | } |
491 | 491 | ||
492 | down(&dir_f->sem); | 492 | mutex_lock(&dir_f->sem); |
493 | 493 | ||
494 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 494 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
495 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); | 495 | rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); |
@@ -513,7 +513,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
513 | /* dirent failed to write. Delete the inode normally | 513 | /* dirent failed to write. Delete the inode normally |
514 | as if it were the final unlink() */ | 514 | as if it were the final unlink() */ |
515 | jffs2_complete_reservation(c); | 515 | jffs2_complete_reservation(c); |
516 | up(&dir_f->sem); | 516 | mutex_unlock(&dir_f->sem); |
517 | return PTR_ERR(fd); | 517 | return PTR_ERR(fd); |
518 | } | 518 | } |
519 | 519 | ||
@@ -522,7 +522,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str | |||
522 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | 522 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); |
523 | 523 | ||
524 | jffs2_complete_reservation(c); | 524 | jffs2_complete_reservation(c); |
525 | up(&dir_f->sem); | 525 | mutex_unlock(&dir_f->sem); |
526 | 526 | ||
527 | return 0; | 527 | return 0; |
528 | } | 528 | } |
@@ -551,7 +551,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
551 | return ret; | 551 | return ret; |
552 | } | 552 | } |
553 | 553 | ||
554 | down(&dir_f->sem); | 554 | mutex_lock(&dir_f->sem); |
555 | 555 | ||
556 | /* Build a deletion node */ | 556 | /* Build a deletion node */ |
557 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 557 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
@@ -574,21 +574,21 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
574 | 574 | ||
575 | if (IS_ERR(fd)) { | 575 | if (IS_ERR(fd)) { |
576 | jffs2_complete_reservation(c); | 576 | jffs2_complete_reservation(c); |
577 | up(&dir_f->sem); | 577 | mutex_unlock(&dir_f->sem); |
578 | return PTR_ERR(fd); | 578 | return PTR_ERR(fd); |
579 | } | 579 | } |
580 | 580 | ||
581 | /* File it. This will mark the old one obsolete. */ | 581 | /* File it. This will mark the old one obsolete. */ |
582 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | 582 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); |
583 | up(&dir_f->sem); | 583 | mutex_unlock(&dir_f->sem); |
584 | } else { | 584 | } else { |
585 | struct jffs2_full_dirent *fd = dir_f->dents; | ||
586 | uint32_t nhash = full_name_hash(name, namelen); | 585 | uint32_t nhash = full_name_hash(name, namelen); |
587 | 586 | ||
587 | fd = dir_f->dents; | ||
588 | /* We don't actually want to reserve any space, but we do | 588 | /* We don't actually want to reserve any space, but we do |
589 | want to be holding the alloc_sem when we write to flash */ | 589 | want to be holding the alloc_sem when we write to flash */ |
590 | down(&c->alloc_sem); | 590 | mutex_lock(&c->alloc_sem); |
591 | down(&dir_f->sem); | 591 | mutex_lock(&dir_f->sem); |
592 | 592 | ||
593 | for (fd = dir_f->dents; fd; fd = fd->next) { | 593 | for (fd = dir_f->dents; fd; fd = fd->next) { |
594 | if (fd->nhash == nhash && | 594 | if (fd->nhash == nhash && |
@@ -607,7 +607,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
607 | break; | 607 | break; |
608 | } | 608 | } |
609 | } | 609 | } |
610 | up(&dir_f->sem); | 610 | mutex_unlock(&dir_f->sem); |
611 | } | 611 | } |
612 | 612 | ||
613 | /* dead_f is NULL if this was a rename not a real unlink */ | 613 | /* dead_f is NULL if this was a rename not a real unlink */ |
@@ -615,7 +615,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
615 | pointing to an inode which didn't exist. */ | 615 | pointing to an inode which didn't exist. */ |
616 | if (dead_f && dead_f->inocache) { | 616 | if (dead_f && dead_f->inocache) { |
617 | 617 | ||
618 | down(&dead_f->sem); | 618 | mutex_lock(&dead_f->sem); |
619 | 619 | ||
620 | if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) { | 620 | if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) { |
621 | while (dead_f->dents) { | 621 | while (dead_f->dents) { |
@@ -639,7 +639,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
639 | 639 | ||
640 | dead_f->inocache->nlink--; | 640 | dead_f->inocache->nlink--; |
641 | /* NB: Caller must set inode nlink if appropriate */ | 641 | /* NB: Caller must set inode nlink if appropriate */ |
642 | up(&dead_f->sem); | 642 | mutex_unlock(&dead_f->sem); |
643 | } | 643 | } |
644 | 644 | ||
645 | jffs2_complete_reservation(c); | 645 | jffs2_complete_reservation(c); |
@@ -666,7 +666,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint | |||
666 | return ret; | 666 | return ret; |
667 | } | 667 | } |
668 | 668 | ||
669 | down(&dir_f->sem); | 669 | mutex_lock(&dir_f->sem); |
670 | 670 | ||
671 | /* Build a deletion node */ | 671 | /* Build a deletion node */ |
672 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 672 | rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
@@ -691,7 +691,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint | |||
691 | 691 | ||
692 | if (IS_ERR(fd)) { | 692 | if (IS_ERR(fd)) { |
693 | jffs2_complete_reservation(c); | 693 | jffs2_complete_reservation(c); |
694 | up(&dir_f->sem); | 694 | mutex_unlock(&dir_f->sem); |
695 | return PTR_ERR(fd); | 695 | return PTR_ERR(fd); |
696 | } | 696 | } |
697 | 697 | ||
@@ -699,7 +699,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint | |||
699 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | 699 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); |
700 | 700 | ||
701 | jffs2_complete_reservation(c); | 701 | jffs2_complete_reservation(c); |
702 | up(&dir_f->sem); | 702 | mutex_unlock(&dir_f->sem); |
703 | 703 | ||
704 | return 0; | 704 | return 0; |
705 | } | 705 | } |
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index b6b74a60e1eb..40b16f23e49a 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -155,8 +155,6 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req) | |||
155 | int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | 155 | int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) |
156 | { | 156 | { |
157 | struct nlm_rqst *call; | 157 | struct nlm_rqst *call; |
158 | sigset_t oldset; | ||
159 | unsigned long flags; | ||
160 | int status; | 158 | int status; |
161 | 159 | ||
162 | nlm_get_host(host); | 160 | nlm_get_host(host); |
@@ -168,22 +166,6 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | |||
168 | /* Set up the argument struct */ | 166 | /* Set up the argument struct */ |
169 | nlmclnt_setlockargs(call, fl); | 167 | nlmclnt_setlockargs(call, fl); |
170 | 168 | ||
171 | /* Keep the old signal mask */ | ||
172 | spin_lock_irqsave(¤t->sighand->siglock, flags); | ||
173 | oldset = current->blocked; | ||
174 | |||
175 | /* If we're cleaning up locks because the process is exiting, | ||
176 | * perform the RPC call asynchronously. */ | ||
177 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) | ||
178 | && fl->fl_type == F_UNLCK | ||
179 | && (current->flags & PF_EXITING)) { | ||
180 | sigfillset(¤t->blocked); /* Mask all signals */ | ||
181 | recalc_sigpending(); | ||
182 | |||
183 | call->a_flags = RPC_TASK_ASYNC; | ||
184 | } | ||
185 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
186 | |||
187 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { | 169 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { |
188 | if (fl->fl_type != F_UNLCK) { | 170 | if (fl->fl_type != F_UNLCK) { |
189 | call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; | 171 | call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; |
@@ -198,11 +180,6 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | |||
198 | fl->fl_ops->fl_release_private(fl); | 180 | fl->fl_ops->fl_release_private(fl); |
199 | fl->fl_ops = NULL; | 181 | fl->fl_ops = NULL; |
200 | 182 | ||
201 | spin_lock_irqsave(¤t->sighand->siglock, flags); | ||
202 | current->blocked = oldset; | ||
203 | recalc_sigpending(); | ||
204 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
205 | |||
206 | dprintk("lockd: clnt proc returns %d\n", status); | 183 | dprintk("lockd: clnt proc returns %d\n", status); |
207 | return status; | 184 | return status; |
208 | } | 185 | } |
@@ -221,6 +198,7 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host) | |||
221 | for(;;) { | 198 | for(;;) { |
222 | call = kzalloc(sizeof(*call), GFP_KERNEL); | 199 | call = kzalloc(sizeof(*call), GFP_KERNEL); |
223 | if (call != NULL) { | 200 | if (call != NULL) { |
201 | atomic_set(&call->a_count, 1); | ||
224 | locks_init_lock(&call->a_args.lock.fl); | 202 | locks_init_lock(&call->a_args.lock.fl); |
225 | locks_init_lock(&call->a_res.lock.fl); | 203 | locks_init_lock(&call->a_res.lock.fl); |
226 | call->a_host = host; | 204 | call->a_host = host; |
@@ -237,6 +215,8 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host) | |||
237 | 215 | ||
238 | void nlm_release_call(struct nlm_rqst *call) | 216 | void nlm_release_call(struct nlm_rqst *call) |
239 | { | 217 | { |
218 | if (!atomic_dec_and_test(&call->a_count)) | ||
219 | return; | ||
240 | nlm_release_host(call->a_host); | 220 | nlm_release_host(call->a_host); |
241 | nlmclnt_release_lockargs(call); | 221 | nlmclnt_release_lockargs(call); |
242 | kfree(call); | 222 | kfree(call); |
@@ -267,7 +247,7 @@ static int nlm_wait_on_grace(wait_queue_head_t *queue) | |||
267 | * Generic NLM call | 247 | * Generic NLM call |
268 | */ | 248 | */ |
269 | static int | 249 | static int |
270 | nlmclnt_call(struct nlm_rqst *req, u32 proc) | 250 | nlmclnt_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc) |
271 | { | 251 | { |
272 | struct nlm_host *host = req->a_host; | 252 | struct nlm_host *host = req->a_host; |
273 | struct rpc_clnt *clnt; | 253 | struct rpc_clnt *clnt; |
@@ -276,6 +256,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc) | |||
276 | struct rpc_message msg = { | 256 | struct rpc_message msg = { |
277 | .rpc_argp = argp, | 257 | .rpc_argp = argp, |
278 | .rpc_resp = resp, | 258 | .rpc_resp = resp, |
259 | .rpc_cred = cred, | ||
279 | }; | 260 | }; |
280 | int status; | 261 | int status; |
281 | 262 | ||
@@ -343,10 +324,16 @@ in_grace_period: | |||
343 | /* | 324 | /* |
344 | * Generic NLM call, async version. | 325 | * Generic NLM call, async version. |
345 | */ | 326 | */ |
346 | static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) | 327 | static struct rpc_task *__nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) |
347 | { | 328 | { |
348 | struct nlm_host *host = req->a_host; | 329 | struct nlm_host *host = req->a_host; |
349 | struct rpc_clnt *clnt; | 330 | struct rpc_clnt *clnt; |
331 | struct rpc_task_setup task_setup_data = { | ||
332 | .rpc_message = msg, | ||
333 | .callback_ops = tk_ops, | ||
334 | .callback_data = req, | ||
335 | .flags = RPC_TASK_ASYNC, | ||
336 | }; | ||
350 | 337 | ||
351 | dprintk("lockd: call procedure %d on %s (async)\n", | 338 | dprintk("lockd: call procedure %d on %s (async)\n", |
352 | (int)proc, host->h_name); | 339 | (int)proc, host->h_name); |
@@ -356,21 +343,36 @@ static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message * | |||
356 | if (clnt == NULL) | 343 | if (clnt == NULL) |
357 | goto out_err; | 344 | goto out_err; |
358 | msg->rpc_proc = &clnt->cl_procinfo[proc]; | 345 | msg->rpc_proc = &clnt->cl_procinfo[proc]; |
346 | task_setup_data.rpc_client = clnt; | ||
359 | 347 | ||
360 | /* bootstrap and kick off the async RPC call */ | 348 | /* bootstrap and kick off the async RPC call */ |
361 | return rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req); | 349 | return rpc_run_task(&task_setup_data); |
362 | out_err: | 350 | out_err: |
363 | tk_ops->rpc_release(req); | 351 | tk_ops->rpc_release(req); |
364 | return -ENOLCK; | 352 | return ERR_PTR(-ENOLCK); |
365 | } | 353 | } |
366 | 354 | ||
355 | static int nlm_do_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) | ||
356 | { | ||
357 | struct rpc_task *task; | ||
358 | |||
359 | task = __nlm_async_call(req, proc, msg, tk_ops); | ||
360 | if (IS_ERR(task)) | ||
361 | return PTR_ERR(task); | ||
362 | rpc_put_task(task); | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | /* | ||
367 | * NLM asynchronous call. | ||
368 | */ | ||
367 | int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | 369 | int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
368 | { | 370 | { |
369 | struct rpc_message msg = { | 371 | struct rpc_message msg = { |
370 | .rpc_argp = &req->a_args, | 372 | .rpc_argp = &req->a_args, |
371 | .rpc_resp = &req->a_res, | 373 | .rpc_resp = &req->a_res, |
372 | }; | 374 | }; |
373 | return __nlm_async_call(req, proc, &msg, tk_ops); | 375 | return nlm_do_async_call(req, proc, &msg, tk_ops); |
374 | } | 376 | } |
375 | 377 | ||
376 | int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | 378 | int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
@@ -378,7 +380,33 @@ int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *t | |||
378 | struct rpc_message msg = { | 380 | struct rpc_message msg = { |
379 | .rpc_argp = &req->a_res, | 381 | .rpc_argp = &req->a_res, |
380 | }; | 382 | }; |
381 | return __nlm_async_call(req, proc, &msg, tk_ops); | 383 | return nlm_do_async_call(req, proc, &msg, tk_ops); |
384 | } | ||
385 | |||
386 | /* | ||
387 | * NLM client asynchronous call. | ||
388 | * | ||
389 | * Note that although the calls are asynchronous, and are therefore | ||
390 | * guaranteed to complete, we still always attempt to wait for | ||
391 | * completion in order to be able to correctly track the lock | ||
392 | * state. | ||
393 | */ | ||
394 | static int nlmclnt_async_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | ||
395 | { | ||
396 | struct rpc_message msg = { | ||
397 | .rpc_argp = &req->a_args, | ||
398 | .rpc_resp = &req->a_res, | ||
399 | .rpc_cred = cred, | ||
400 | }; | ||
401 | struct rpc_task *task; | ||
402 | int err; | ||
403 | |||
404 | task = __nlm_async_call(req, proc, &msg, tk_ops); | ||
405 | if (IS_ERR(task)) | ||
406 | return PTR_ERR(task); | ||
407 | err = rpc_wait_for_completion_task(task); | ||
408 | rpc_put_task(task); | ||
409 | return err; | ||
382 | } | 410 | } |
383 | 411 | ||
384 | /* | 412 | /* |
@@ -389,7 +417,7 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) | |||
389 | { | 417 | { |
390 | int status; | 418 | int status; |
391 | 419 | ||
392 | status = nlmclnt_call(req, NLMPROC_TEST); | 420 | status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_TEST); |
393 | if (status < 0) | 421 | if (status < 0) |
394 | goto out; | 422 | goto out; |
395 | 423 | ||
@@ -480,10 +508,12 @@ static int do_vfs_lock(struct file_lock *fl) | |||
480 | static int | 508 | static int |
481 | nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | 509 | nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) |
482 | { | 510 | { |
511 | struct rpc_cred *cred = nfs_file_cred(fl->fl_file); | ||
483 | struct nlm_host *host = req->a_host; | 512 | struct nlm_host *host = req->a_host; |
484 | struct nlm_res *resp = &req->a_res; | 513 | struct nlm_res *resp = &req->a_res; |
485 | struct nlm_wait *block = NULL; | 514 | struct nlm_wait *block = NULL; |
486 | unsigned char fl_flags = fl->fl_flags; | 515 | unsigned char fl_flags = fl->fl_flags; |
516 | unsigned char fl_type; | ||
487 | int status = -ENOLCK; | 517 | int status = -ENOLCK; |
488 | 518 | ||
489 | if (nsm_monitor(host) < 0) { | 519 | if (nsm_monitor(host) < 0) { |
@@ -493,18 +523,22 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
493 | } | 523 | } |
494 | fl->fl_flags |= FL_ACCESS; | 524 | fl->fl_flags |= FL_ACCESS; |
495 | status = do_vfs_lock(fl); | 525 | status = do_vfs_lock(fl); |
526 | fl->fl_flags = fl_flags; | ||
496 | if (status < 0) | 527 | if (status < 0) |
497 | goto out; | 528 | goto out; |
498 | 529 | ||
499 | block = nlmclnt_prepare_block(host, fl); | 530 | block = nlmclnt_prepare_block(host, fl); |
500 | again: | 531 | again: |
532 | /* | ||
533 | * Initialise resp->status to a valid non-zero value, | ||
534 | * since 0 == nlm_lck_granted | ||
535 | */ | ||
536 | resp->status = nlm_lck_blocked; | ||
501 | for(;;) { | 537 | for(;;) { |
502 | /* Reboot protection */ | 538 | /* Reboot protection */ |
503 | fl->fl_u.nfs_fl.state = host->h_state; | 539 | fl->fl_u.nfs_fl.state = host->h_state; |
504 | status = nlmclnt_call(req, NLMPROC_LOCK); | 540 | status = nlmclnt_call(cred, req, NLMPROC_LOCK); |
505 | if (status < 0) | 541 | if (status < 0) |
506 | goto out_unblock; | ||
507 | if (!req->a_args.block) | ||
508 | break; | 542 | break; |
509 | /* Did a reclaimer thread notify us of a server reboot? */ | 543 | /* Did a reclaimer thread notify us of a server reboot? */ |
510 | if (resp->status == nlm_lck_denied_grace_period) | 544 | if (resp->status == nlm_lck_denied_grace_period) |
@@ -513,15 +547,22 @@ again: | |||
513 | break; | 547 | break; |
514 | /* Wait on an NLM blocking lock */ | 548 | /* Wait on an NLM blocking lock */ |
515 | status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); | 549 | status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); |
516 | /* if we were interrupted. Send a CANCEL request to the server | ||
517 | * and exit | ||
518 | */ | ||
519 | if (status < 0) | 550 | if (status < 0) |
520 | goto out_unblock; | 551 | break; |
521 | if (resp->status != nlm_lck_blocked) | 552 | if (resp->status != nlm_lck_blocked) |
522 | break; | 553 | break; |
523 | } | 554 | } |
524 | 555 | ||
556 | /* if we were interrupted while blocking, then cancel the lock request | ||
557 | * and exit | ||
558 | */ | ||
559 | if (resp->status == nlm_lck_blocked) { | ||
560 | if (!req->a_args.block) | ||
561 | goto out_unlock; | ||
562 | if (nlmclnt_cancel(host, req->a_args.block, fl) == 0) | ||
563 | goto out_unblock; | ||
564 | } | ||
565 | |||
525 | if (resp->status == nlm_granted) { | 566 | if (resp->status == nlm_granted) { |
526 | down_read(&host->h_rwsem); | 567 | down_read(&host->h_rwsem); |
527 | /* Check whether or not the server has rebooted */ | 568 | /* Check whether or not the server has rebooted */ |
@@ -530,20 +571,34 @@ again: | |||
530 | goto again; | 571 | goto again; |
531 | } | 572 | } |
532 | /* Ensure the resulting lock will get added to granted list */ | 573 | /* Ensure the resulting lock will get added to granted list */ |
533 | fl->fl_flags = fl_flags | FL_SLEEP; | 574 | fl->fl_flags |= FL_SLEEP; |
534 | if (do_vfs_lock(fl) < 0) | 575 | if (do_vfs_lock(fl) < 0) |
535 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); | 576 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); |
536 | up_read(&host->h_rwsem); | 577 | up_read(&host->h_rwsem); |
578 | fl->fl_flags = fl_flags; | ||
579 | status = 0; | ||
537 | } | 580 | } |
581 | if (status < 0) | ||
582 | goto out_unlock; | ||
538 | status = nlm_stat_to_errno(resp->status); | 583 | status = nlm_stat_to_errno(resp->status); |
539 | out_unblock: | 584 | out_unblock: |
540 | nlmclnt_finish_block(block); | 585 | nlmclnt_finish_block(block); |
541 | /* Cancel the blocked request if it is still pending */ | ||
542 | if (resp->status == nlm_lck_blocked) | ||
543 | nlmclnt_cancel(host, req->a_args.block, fl); | ||
544 | out: | 586 | out: |
545 | nlm_release_call(req); | 587 | nlm_release_call(req); |
588 | return status; | ||
589 | out_unlock: | ||
590 | /* Fatal error: ensure that we remove the lock altogether */ | ||
591 | dprintk("lockd: lock attempt ended in fatal error.\n" | ||
592 | " Attempting to unlock.\n"); | ||
593 | nlmclnt_finish_block(block); | ||
594 | fl_type = fl->fl_type; | ||
595 | fl->fl_type = F_UNLCK; | ||
596 | down_read(&host->h_rwsem); | ||
597 | do_vfs_lock(fl); | ||
598 | up_read(&host->h_rwsem); | ||
599 | fl->fl_type = fl_type; | ||
546 | fl->fl_flags = fl_flags; | 600 | fl->fl_flags = fl_flags; |
601 | nlmclnt_async_call(cred, req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); | ||
547 | return status; | 602 | return status; |
548 | } | 603 | } |
549 | 604 | ||
@@ -567,8 +622,8 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl) | |||
567 | nlmclnt_setlockargs(req, fl); | 622 | nlmclnt_setlockargs(req, fl); |
568 | req->a_args.reclaim = 1; | 623 | req->a_args.reclaim = 1; |
569 | 624 | ||
570 | if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0 | 625 | status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_LOCK); |
571 | && req->a_res.status == nlm_granted) | 626 | if (status >= 0 && req->a_res.status == nlm_granted) |
572 | return 0; | 627 | return 0; |
573 | 628 | ||
574 | printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d " | 629 | printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d " |
@@ -598,7 +653,8 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
598 | { | 653 | { |
599 | struct nlm_host *host = req->a_host; | 654 | struct nlm_host *host = req->a_host; |
600 | struct nlm_res *resp = &req->a_res; | 655 | struct nlm_res *resp = &req->a_res; |
601 | int status = 0; | 656 | int status; |
657 | unsigned char fl_flags = fl->fl_flags; | ||
602 | 658 | ||
603 | /* | 659 | /* |
604 | * Note: the server is supposed to either grant us the unlock | 660 | * Note: the server is supposed to either grant us the unlock |
@@ -607,16 +663,17 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
607 | */ | 663 | */ |
608 | fl->fl_flags |= FL_EXISTS; | 664 | fl->fl_flags |= FL_EXISTS; |
609 | down_read(&host->h_rwsem); | 665 | down_read(&host->h_rwsem); |
610 | if (do_vfs_lock(fl) == -ENOENT) { | 666 | status = do_vfs_lock(fl); |
611 | up_read(&host->h_rwsem); | 667 | up_read(&host->h_rwsem); |
668 | fl->fl_flags = fl_flags; | ||
669 | if (status == -ENOENT) { | ||
670 | status = 0; | ||
612 | goto out; | 671 | goto out; |
613 | } | 672 | } |
614 | up_read(&host->h_rwsem); | ||
615 | |||
616 | if (req->a_flags & RPC_TASK_ASYNC) | ||
617 | return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); | ||
618 | 673 | ||
619 | status = nlmclnt_call(req, NLMPROC_UNLOCK); | 674 | atomic_inc(&req->a_count); |
675 | status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req, | ||
676 | NLMPROC_UNLOCK, &nlmclnt_unlock_ops); | ||
620 | if (status < 0) | 677 | if (status < 0) |
621 | goto out; | 678 | goto out; |
622 | 679 | ||
@@ -671,16 +728,10 @@ static const struct rpc_call_ops nlmclnt_unlock_ops = { | |||
671 | static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl) | 728 | static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl) |
672 | { | 729 | { |
673 | struct nlm_rqst *req; | 730 | struct nlm_rqst *req; |
674 | unsigned long flags; | 731 | int status; |
675 | sigset_t oldset; | ||
676 | int status; | ||
677 | 732 | ||
678 | /* Block all signals while setting up call */ | 733 | dprintk("lockd: blocking lock attempt was interrupted by a signal.\n" |
679 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 734 | " Attempting to cancel lock.\n"); |
680 | oldset = current->blocked; | ||
681 | sigfillset(¤t->blocked); | ||
682 | recalc_sigpending(); | ||
683 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
684 | 735 | ||
685 | req = nlm_alloc_call(nlm_get_host(host)); | 736 | req = nlm_alloc_call(nlm_get_host(host)); |
686 | if (!req) | 737 | if (!req) |
@@ -690,13 +741,12 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl | |||
690 | nlmclnt_setlockargs(req, fl); | 741 | nlmclnt_setlockargs(req, fl); |
691 | req->a_args.block = block; | 742 | req->a_args.block = block; |
692 | 743 | ||
693 | status = nlm_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops); | 744 | atomic_inc(&req->a_count); |
694 | 745 | status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req, | |
695 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 746 | NLMPROC_CANCEL, &nlmclnt_cancel_ops); |
696 | current->blocked = oldset; | 747 | if (status == 0 && req->a_res.status == nlm_lck_denied) |
697 | recalc_sigpending(); | 748 | status = -ENOLCK; |
698 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 749 | nlm_release_call(req); |
699 | |||
700 | return status; | 750 | return status; |
701 | } | 751 | } |
702 | 752 | ||
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index f1ef49fff118..a17664c7eacc 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -19,12 +19,11 @@ | |||
19 | 19 | ||
20 | 20 | ||
21 | #define NLMDBG_FACILITY NLMDBG_HOSTCACHE | 21 | #define NLMDBG_FACILITY NLMDBG_HOSTCACHE |
22 | #define NLM_HOST_MAX 64 | ||
23 | #define NLM_HOST_NRHASH 32 | 22 | #define NLM_HOST_NRHASH 32 |
24 | #define NLM_ADDRHASH(addr) (ntohl(addr) & (NLM_HOST_NRHASH-1)) | 23 | #define NLM_ADDRHASH(addr) (ntohl(addr) & (NLM_HOST_NRHASH-1)) |
25 | #define NLM_HOST_REBIND (60 * HZ) | 24 | #define NLM_HOST_REBIND (60 * HZ) |
26 | #define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ) | 25 | #define NLM_HOST_EXPIRE (300 * HZ) |
27 | #define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ) | 26 | #define NLM_HOST_COLLECT (120 * HZ) |
28 | 27 | ||
29 | static struct hlist_head nlm_hosts[NLM_HOST_NRHASH]; | 28 | static struct hlist_head nlm_hosts[NLM_HOST_NRHASH]; |
30 | static unsigned long next_gc; | 29 | static unsigned long next_gc; |
@@ -42,11 +41,12 @@ static struct nsm_handle * nsm_find(const struct sockaddr_in *sin, | |||
42 | /* | 41 | /* |
43 | * Common host lookup routine for server & client | 42 | * Common host lookup routine for server & client |
44 | */ | 43 | */ |
45 | static struct nlm_host * | 44 | static struct nlm_host *nlm_lookup_host(int server, |
46 | nlm_lookup_host(int server, const struct sockaddr_in *sin, | 45 | const struct sockaddr_in *sin, |
47 | int proto, int version, const char *hostname, | 46 | int proto, u32 version, |
48 | unsigned int hostname_len, | 47 | const char *hostname, |
49 | const struct sockaddr_in *ssin) | 48 | unsigned int hostname_len, |
49 | const struct sockaddr_in *ssin) | ||
50 | { | 50 | { |
51 | struct hlist_head *chain; | 51 | struct hlist_head *chain; |
52 | struct hlist_node *pos; | 52 | struct hlist_node *pos; |
@@ -55,7 +55,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |||
55 | int hash; | 55 | int hash; |
56 | 56 | ||
57 | dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT | 57 | dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT |
58 | ", p=%d, v=%d, my role=%s, name=%.*s)\n", | 58 | ", p=%d, v=%u, my role=%s, name=%.*s)\n", |
59 | NIPQUAD(ssin->sin_addr.s_addr), | 59 | NIPQUAD(ssin->sin_addr.s_addr), |
60 | NIPQUAD(sin->sin_addr.s_addr), proto, version, | 60 | NIPQUAD(sin->sin_addr.s_addr), proto, version, |
61 | server? "server" : "client", | 61 | server? "server" : "client", |
@@ -142,9 +142,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |||
142 | INIT_LIST_HEAD(&host->h_granted); | 142 | INIT_LIST_HEAD(&host->h_granted); |
143 | INIT_LIST_HEAD(&host->h_reclaim); | 143 | INIT_LIST_HEAD(&host->h_reclaim); |
144 | 144 | ||
145 | if (++nrhosts > NLM_HOST_MAX) | 145 | nrhosts++; |
146 | next_gc = 0; | ||
147 | |||
148 | out: | 146 | out: |
149 | mutex_unlock(&nlm_host_mutex); | 147 | mutex_unlock(&nlm_host_mutex); |
150 | return host; | 148 | return host; |
@@ -175,9 +173,10 @@ nlm_destroy_host(struct nlm_host *host) | |||
175 | /* | 173 | /* |
176 | * Find an NLM server handle in the cache. If there is none, create it. | 174 | * Find an NLM server handle in the cache. If there is none, create it. |
177 | */ | 175 | */ |
178 | struct nlm_host * | 176 | struct nlm_host *nlmclnt_lookup_host(const struct sockaddr_in *sin, |
179 | nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version, | 177 | int proto, u32 version, |
180 | const char *hostname, unsigned int hostname_len) | 178 | const char *hostname, |
179 | unsigned int hostname_len) | ||
181 | { | 180 | { |
182 | struct sockaddr_in ssin = {0}; | 181 | struct sockaddr_in ssin = {0}; |
183 | 182 | ||
@@ -460,7 +459,7 @@ nlm_gc_hosts(void) | |||
460 | * Manage NSM handles | 459 | * Manage NSM handles |
461 | */ | 460 | */ |
462 | static LIST_HEAD(nsm_handles); | 461 | static LIST_HEAD(nsm_handles); |
463 | static DEFINE_MUTEX(nsm_mutex); | 462 | static DEFINE_SPINLOCK(nsm_lock); |
464 | 463 | ||
465 | static struct nsm_handle * | 464 | static struct nsm_handle * |
466 | __nsm_find(const struct sockaddr_in *sin, | 465 | __nsm_find(const struct sockaddr_in *sin, |
@@ -468,7 +467,7 @@ __nsm_find(const struct sockaddr_in *sin, | |||
468 | int create) | 467 | int create) |
469 | { | 468 | { |
470 | struct nsm_handle *nsm = NULL; | 469 | struct nsm_handle *nsm = NULL; |
471 | struct list_head *pos; | 470 | struct nsm_handle *pos; |
472 | 471 | ||
473 | if (!sin) | 472 | if (!sin) |
474 | return NULL; | 473 | return NULL; |
@@ -482,38 +481,43 @@ __nsm_find(const struct sockaddr_in *sin, | |||
482 | return NULL; | 481 | return NULL; |
483 | } | 482 | } |
484 | 483 | ||
485 | mutex_lock(&nsm_mutex); | 484 | retry: |
486 | list_for_each(pos, &nsm_handles) { | 485 | spin_lock(&nsm_lock); |
487 | nsm = list_entry(pos, struct nsm_handle, sm_link); | 486 | list_for_each_entry(pos, &nsm_handles, sm_link) { |
488 | 487 | ||
489 | if (hostname && nsm_use_hostnames) { | 488 | if (hostname && nsm_use_hostnames) { |
490 | if (strlen(nsm->sm_name) != hostname_len | 489 | if (strlen(pos->sm_name) != hostname_len |
491 | || memcmp(nsm->sm_name, hostname, hostname_len)) | 490 | || memcmp(pos->sm_name, hostname, hostname_len)) |
492 | continue; | 491 | continue; |
493 | } else if (!nlm_cmp_addr(&nsm->sm_addr, sin)) | 492 | } else if (!nlm_cmp_addr(&pos->sm_addr, sin)) |
494 | continue; | 493 | continue; |
495 | atomic_inc(&nsm->sm_count); | 494 | atomic_inc(&pos->sm_count); |
496 | goto out; | 495 | kfree(nsm); |
496 | nsm = pos; | ||
497 | goto found; | ||
497 | } | 498 | } |
498 | 499 | if (nsm) { | |
499 | if (!create) { | 500 | list_add(&nsm->sm_link, &nsm_handles); |
500 | nsm = NULL; | 501 | goto found; |
501 | goto out; | ||
502 | } | 502 | } |
503 | spin_unlock(&nsm_lock); | ||
504 | |||
505 | if (!create) | ||
506 | return NULL; | ||
503 | 507 | ||
504 | nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL); | 508 | nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL); |
505 | if (nsm != NULL) { | 509 | if (nsm == NULL) |
506 | nsm->sm_addr = *sin; | 510 | return NULL; |
507 | nsm->sm_name = (char *) (nsm + 1); | ||
508 | memcpy(nsm->sm_name, hostname, hostname_len); | ||
509 | nsm->sm_name[hostname_len] = '\0'; | ||
510 | atomic_set(&nsm->sm_count, 1); | ||
511 | 511 | ||
512 | list_add(&nsm->sm_link, &nsm_handles); | 512 | nsm->sm_addr = *sin; |
513 | } | 513 | nsm->sm_name = (char *) (nsm + 1); |
514 | memcpy(nsm->sm_name, hostname, hostname_len); | ||
515 | nsm->sm_name[hostname_len] = '\0'; | ||
516 | atomic_set(&nsm->sm_count, 1); | ||
517 | goto retry; | ||
514 | 518 | ||
515 | out: | 519 | found: |
516 | mutex_unlock(&nsm_mutex); | 520 | spin_unlock(&nsm_lock); |
517 | return nsm; | 521 | return nsm; |
518 | } | 522 | } |
519 | 523 | ||
@@ -532,12 +536,9 @@ nsm_release(struct nsm_handle *nsm) | |||
532 | { | 536 | { |
533 | if (!nsm) | 537 | if (!nsm) |
534 | return; | 538 | return; |
535 | if (atomic_dec_and_test(&nsm->sm_count)) { | 539 | if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) { |
536 | mutex_lock(&nsm_mutex); | 540 | list_del(&nsm->sm_link); |
537 | if (atomic_read(&nsm->sm_count) == 0) { | 541 | spin_unlock(&nsm_lock); |
538 | list_del(&nsm->sm_link); | 542 | kfree(nsm); |
539 | kfree(nsm); | ||
540 | } | ||
541 | mutex_unlock(&nsm_mutex); | ||
542 | } | 543 | } |
543 | } | 544 | } |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 908b23fadd05..e4d563543b11 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -18,6 +18,8 @@ | |||
18 | 18 | ||
19 | #define NLMDBG_FACILITY NLMDBG_MONITOR | 19 | #define NLMDBG_FACILITY NLMDBG_MONITOR |
20 | 20 | ||
21 | #define XDR_ADDRBUF_LEN (20) | ||
22 | |||
21 | static struct rpc_clnt * nsm_create(void); | 23 | static struct rpc_clnt * nsm_create(void); |
22 | 24 | ||
23 | static struct rpc_program nsm_program; | 25 | static struct rpc_program nsm_program; |
@@ -147,28 +149,55 @@ nsm_create(void) | |||
147 | 149 | ||
148 | /* | 150 | /* |
149 | * XDR functions for NSM. | 151 | * XDR functions for NSM. |
152 | * | ||
153 | * See http://www.opengroup.org/ for details on the Network | ||
154 | * Status Monitor wire protocol. | ||
150 | */ | 155 | */ |
151 | 156 | ||
152 | static __be32 * | 157 | static __be32 *xdr_encode_nsm_string(__be32 *p, char *string) |
153 | xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | ||
154 | { | 158 | { |
155 | char buffer[20], *name; | 159 | size_t len = strlen(string); |
156 | 160 | ||
157 | /* | 161 | if (len > SM_MAXSTRLEN) |
158 | * Use the dotted-quad IP address of the remote host as | 162 | len = SM_MAXSTRLEN; |
159 | * identifier. Linux statd always looks up the canonical | 163 | return xdr_encode_opaque(p, string, len); |
160 | * hostname first for whatever remote hostname it receives, | 164 | } |
161 | * so this works alright. | 165 | |
162 | */ | 166 | /* |
163 | if (nsm_use_hostnames) { | 167 | * "mon_name" specifies the host to be monitored. |
164 | name = argp->mon_name; | 168 | * |
165 | } else { | 169 | * Linux uses a text version of the IP address of the remote |
166 | sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr)); | 170 | * host as the host identifier (the "mon_name" argument). |
171 | * | ||
172 | * Linux statd always looks up the canonical hostname first for | ||
173 | * whatever remote hostname it receives, so this works alright. | ||
174 | */ | ||
175 | static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) | ||
176 | { | ||
177 | char buffer[XDR_ADDRBUF_LEN + 1]; | ||
178 | char *name = argp->mon_name; | ||
179 | |||
180 | if (!nsm_use_hostnames) { | ||
181 | snprintf(buffer, XDR_ADDRBUF_LEN, | ||
182 | NIPQUAD_FMT, NIPQUAD(argp->addr)); | ||
167 | name = buffer; | 183 | name = buffer; |
168 | } | 184 | } |
169 | if (!(p = xdr_encode_string(p, name)) | 185 | |
170 | || !(p = xdr_encode_string(p, utsname()->nodename))) | 186 | return xdr_encode_nsm_string(p, name); |
187 | } | ||
188 | |||
189 | /* | ||
190 | * The "my_id" argument specifies the hostname and RPC procedure | ||
191 | * to be called when the status manager receives notification | ||
192 | * (via the SM_NOTIFY call) that the state of host "mon_name" | ||
193 | * has changed. | ||
194 | */ | ||
195 | static __be32 *xdr_encode_my_id(__be32 *p, struct nsm_args *argp) | ||
196 | { | ||
197 | p = xdr_encode_nsm_string(p, utsname()->nodename); | ||
198 | if (!p) | ||
171 | return ERR_PTR(-EIO); | 199 | return ERR_PTR(-EIO); |
200 | |||
172 | *p++ = htonl(argp->prog); | 201 | *p++ = htonl(argp->prog); |
173 | *p++ = htonl(argp->vers); | 202 | *p++ = htonl(argp->vers); |
174 | *p++ = htonl(argp->proc); | 203 | *p++ = htonl(argp->proc); |
@@ -176,18 +205,48 @@ xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | |||
176 | return p; | 205 | return p; |
177 | } | 206 | } |
178 | 207 | ||
179 | static int | 208 | /* |
180 | xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | 209 | * The "mon_id" argument specifies the non-private arguments |
210 | * of an SM_MON or SM_UNMON call. | ||
211 | */ | ||
212 | static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp) | ||
181 | { | 213 | { |
182 | p = xdr_encode_common(rqstp, p, argp); | 214 | p = xdr_encode_mon_name(p, argp); |
183 | if (IS_ERR(p)) | 215 | if (!p) |
184 | return PTR_ERR(p); | 216 | return ERR_PTR(-EIO); |
185 | 217 | ||
186 | /* Surprise - there may even be room for an IPv6 address now */ | 218 | return xdr_encode_my_id(p, argp); |
219 | } | ||
220 | |||
221 | /* | ||
222 | * The "priv" argument may contain private information required | ||
223 | * by the SM_MON call. This information will be supplied in the | ||
224 | * SM_NOTIFY call. | ||
225 | * | ||
226 | * Linux provides the raw IP address of the monitored host, | ||
227 | * left in network byte order. | ||
228 | */ | ||
229 | static __be32 *xdr_encode_priv(__be32 *p, struct nsm_args *argp) | ||
230 | { | ||
187 | *p++ = argp->addr; | 231 | *p++ = argp->addr; |
188 | *p++ = 0; | 232 | *p++ = 0; |
189 | *p++ = 0; | 233 | *p++ = 0; |
190 | *p++ = 0; | 234 | *p++ = 0; |
235 | |||
236 | return p; | ||
237 | } | ||
238 | |||
239 | static int | ||
240 | xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | ||
241 | { | ||
242 | p = xdr_encode_mon_id(p, argp); | ||
243 | if (IS_ERR(p)) | ||
244 | return PTR_ERR(p); | ||
245 | |||
246 | p = xdr_encode_priv(p, argp); | ||
247 | if (IS_ERR(p)) | ||
248 | return PTR_ERR(p); | ||
249 | |||
191 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); | 250 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); |
192 | return 0; | 251 | return 0; |
193 | } | 252 | } |
@@ -195,7 +254,7 @@ xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | |||
195 | static int | 254 | static int |
196 | xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | 255 | xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) |
197 | { | 256 | { |
198 | p = xdr_encode_common(rqstp, p, argp); | 257 | p = xdr_encode_mon_id(p, argp); |
199 | if (IS_ERR(p)) | 258 | if (IS_ERR(p)) |
200 | return PTR_ERR(p); | 259 | return PTR_ERR(p); |
201 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); | 260 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); |
@@ -220,9 +279,11 @@ xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) | |||
220 | } | 279 | } |
221 | 280 | ||
222 | #define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) | 281 | #define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) |
223 | #define SM_my_id_sz (3+1+SM_my_name_sz) | 282 | #define SM_my_id_sz (SM_my_name_sz+3) |
224 | #define SM_mon_id_sz (1+XDR_QUADLEN(20)+SM_my_id_sz) | 283 | #define SM_mon_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) |
225 | #define SM_mon_sz (SM_mon_id_sz+4) | 284 | #define SM_mon_id_sz (SM_mon_name_sz+SM_my_id_sz) |
285 | #define SM_priv_sz (XDR_QUADLEN(SM_PRIV_SIZE)) | ||
286 | #define SM_mon_sz (SM_mon_id_sz+SM_priv_sz) | ||
226 | #define SM_monres_sz 2 | 287 | #define SM_monres_sz 2 |
227 | #define SM_unmonres_sz 1 | 288 | #define SM_unmonres_sz 1 |
228 | 289 | ||
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 1ed8bd4de941..2169af4d5455 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/smp.h> | 25 | #include <linux/smp.h> |
26 | #include <linux/smp_lock.h> | 26 | #include <linux/smp_lock.h> |
27 | #include <linux/mutex.h> | 27 | #include <linux/mutex.h> |
28 | #include <linux/kthread.h> | ||
28 | #include <linux/freezer.h> | 29 | #include <linux/freezer.h> |
29 | 30 | ||
30 | #include <linux/sunrpc/types.h> | 31 | #include <linux/sunrpc/types.h> |
@@ -48,14 +49,11 @@ EXPORT_SYMBOL(nlmsvc_ops); | |||
48 | 49 | ||
49 | static DEFINE_MUTEX(nlmsvc_mutex); | 50 | static DEFINE_MUTEX(nlmsvc_mutex); |
50 | static unsigned int nlmsvc_users; | 51 | static unsigned int nlmsvc_users; |
51 | static pid_t nlmsvc_pid; | 52 | static struct task_struct *nlmsvc_task; |
52 | static struct svc_serv *nlmsvc_serv; | 53 | static struct svc_serv *nlmsvc_serv; |
53 | int nlmsvc_grace_period; | 54 | int nlmsvc_grace_period; |
54 | unsigned long nlmsvc_timeout; | 55 | unsigned long nlmsvc_timeout; |
55 | 56 | ||
56 | static DECLARE_COMPLETION(lockd_start_done); | ||
57 | static DECLARE_WAIT_QUEUE_HEAD(lockd_exit); | ||
58 | |||
59 | /* | 57 | /* |
60 | * These can be set at insmod time (useful for NFS as root filesystem), | 58 | * These can be set at insmod time (useful for NFS as root filesystem), |
61 | * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 | 59 | * and also changed through the sysctl interface. -- Jamie Lokier, Aug 2003 |
@@ -74,7 +72,9 @@ static const unsigned long nlm_timeout_min = 3; | |||
74 | static const unsigned long nlm_timeout_max = 20; | 72 | static const unsigned long nlm_timeout_max = 20; |
75 | static const int nlm_port_min = 0, nlm_port_max = 65535; | 73 | static const int nlm_port_min = 0, nlm_port_max = 65535; |
76 | 74 | ||
75 | #ifdef CONFIG_SYSCTL | ||
77 | static struct ctl_table_header * nlm_sysctl_table; | 76 | static struct ctl_table_header * nlm_sysctl_table; |
77 | #endif | ||
78 | 78 | ||
79 | static unsigned long get_lockd_grace_period(void) | 79 | static unsigned long get_lockd_grace_period(void) |
80 | { | 80 | { |
@@ -111,35 +111,30 @@ static inline void clear_grace_period(void) | |||
111 | /* | 111 | /* |
112 | * This is the lockd kernel thread | 112 | * This is the lockd kernel thread |
113 | */ | 113 | */ |
114 | static void | 114 | static int |
115 | lockd(struct svc_rqst *rqstp) | 115 | lockd(void *vrqstp) |
116 | { | 116 | { |
117 | int err = 0; | 117 | int err = 0, preverr = 0; |
118 | struct svc_rqst *rqstp = vrqstp; | ||
118 | unsigned long grace_period_expire; | 119 | unsigned long grace_period_expire; |
119 | 120 | ||
120 | /* Lock module and set up kernel thread */ | 121 | /* try_to_freeze() is called from svc_recv() */ |
121 | /* lockd_up is waiting for us to startup, so will | ||
122 | * be holding a reference to this module, so it | ||
123 | * is safe to just claim another reference | ||
124 | */ | ||
125 | __module_get(THIS_MODULE); | ||
126 | lock_kernel(); | ||
127 | |||
128 | /* | ||
129 | * Let our maker know we're running. | ||
130 | */ | ||
131 | nlmsvc_pid = current->pid; | ||
132 | nlmsvc_serv = rqstp->rq_server; | ||
133 | complete(&lockd_start_done); | ||
134 | |||
135 | daemonize("lockd"); | ||
136 | set_freezable(); | 122 | set_freezable(); |
137 | 123 | ||
138 | /* Process request with signals blocked, but allow SIGKILL. */ | 124 | /* Allow SIGKILL to tell lockd to drop all of its locks */ |
139 | allow_signal(SIGKILL); | 125 | allow_signal(SIGKILL); |
140 | 126 | ||
141 | dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); | 127 | dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); |
142 | 128 | ||
129 | /* | ||
130 | * FIXME: it would be nice if lockd didn't spend its entire life | ||
131 | * running under the BKL. At the very least, it would be good to | ||
132 | * have someone clarify what it's intended to protect here. I've | ||
133 | * seen some handwavy posts about posix locking needing to be | ||
134 | * done under the BKL, but it's far from clear. | ||
135 | */ | ||
136 | lock_kernel(); | ||
137 | |||
143 | if (!nlm_timeout) | 138 | if (!nlm_timeout) |
144 | nlm_timeout = LOCKD_DFLT_TIMEO; | 139 | nlm_timeout = LOCKD_DFLT_TIMEO; |
145 | nlmsvc_timeout = nlm_timeout * HZ; | 140 | nlmsvc_timeout = nlm_timeout * HZ; |
@@ -148,10 +143,9 @@ lockd(struct svc_rqst *rqstp) | |||
148 | 143 | ||
149 | /* | 144 | /* |
150 | * The main request loop. We don't terminate until the last | 145 | * The main request loop. We don't terminate until the last |
151 | * NFS mount or NFS daemon has gone away, and we've been sent a | 146 | * NFS mount or NFS daemon has gone away. |
152 | * signal, or else another process has taken over our job. | ||
153 | */ | 147 | */ |
154 | while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { | 148 | while (!kthread_should_stop()) { |
155 | long timeout = MAX_SCHEDULE_TIMEOUT; | 149 | long timeout = MAX_SCHEDULE_TIMEOUT; |
156 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); | 150 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); |
157 | 151 | ||
@@ -161,6 +155,7 @@ lockd(struct svc_rqst *rqstp) | |||
161 | nlmsvc_invalidate_all(); | 155 | nlmsvc_invalidate_all(); |
162 | grace_period_expire = set_grace_period(); | 156 | grace_period_expire = set_grace_period(); |
163 | } | 157 | } |
158 | continue; | ||
164 | } | 159 | } |
165 | 160 | ||
166 | /* | 161 | /* |
@@ -179,14 +174,20 @@ lockd(struct svc_rqst *rqstp) | |||
179 | * recvfrom routine. | 174 | * recvfrom routine. |
180 | */ | 175 | */ |
181 | err = svc_recv(rqstp, timeout); | 176 | err = svc_recv(rqstp, timeout); |
182 | if (err == -EAGAIN || err == -EINTR) | 177 | if (err == -EAGAIN || err == -EINTR) { |
178 | preverr = err; | ||
183 | continue; | 179 | continue; |
180 | } | ||
184 | if (err < 0) { | 181 | if (err < 0) { |
185 | printk(KERN_WARNING | 182 | if (err != preverr) { |
186 | "lockd: terminating on error %d\n", | 183 | printk(KERN_WARNING "%s: unexpected error " |
187 | -err); | 184 | "from svc_recv (%d)\n", __func__, err); |
188 | break; | 185 | preverr = err; |
186 | } | ||
187 | schedule_timeout_interruptible(HZ); | ||
188 | continue; | ||
189 | } | 189 | } |
190 | preverr = err; | ||
190 | 191 | ||
191 | dprintk("lockd: request from %s\n", | 192 | dprintk("lockd: request from %s\n", |
192 | svc_print_addr(rqstp, buf, sizeof(buf))); | 193 | svc_print_addr(rqstp, buf, sizeof(buf))); |
@@ -195,28 +196,19 @@ lockd(struct svc_rqst *rqstp) | |||
195 | } | 196 | } |
196 | 197 | ||
197 | flush_signals(current); | 198 | flush_signals(current); |
199 | if (nlmsvc_ops) | ||
200 | nlmsvc_invalidate_all(); | ||
201 | nlm_shutdown_hosts(); | ||
198 | 202 | ||
199 | /* | 203 | unlock_kernel(); |
200 | * Check whether there's a new lockd process before | 204 | |
201 | * shutting down the hosts and clearing the slot. | 205 | nlmsvc_task = NULL; |
202 | */ | 206 | nlmsvc_serv = NULL; |
203 | if (!nlmsvc_pid || current->pid == nlmsvc_pid) { | ||
204 | if (nlmsvc_ops) | ||
205 | nlmsvc_invalidate_all(); | ||
206 | nlm_shutdown_hosts(); | ||
207 | nlmsvc_pid = 0; | ||
208 | nlmsvc_serv = NULL; | ||
209 | } else | ||
210 | printk(KERN_DEBUG | ||
211 | "lockd: new process, skipping host shutdown\n"); | ||
212 | wake_up(&lockd_exit); | ||
213 | 207 | ||
214 | /* Exit the RPC thread */ | 208 | /* Exit the RPC thread */ |
215 | svc_exit_thread(rqstp); | 209 | svc_exit_thread(rqstp); |
216 | 210 | ||
217 | /* Release module */ | 211 | return 0; |
218 | unlock_kernel(); | ||
219 | module_put_and_exit(0); | ||
220 | } | 212 | } |
221 | 213 | ||
222 | /* | 214 | /* |
@@ -261,14 +253,15 @@ static int make_socks(struct svc_serv *serv, int proto) | |||
261 | int | 253 | int |
262 | lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ | 254 | lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ |
263 | { | 255 | { |
264 | struct svc_serv * serv; | 256 | struct svc_serv *serv; |
265 | int error = 0; | 257 | struct svc_rqst *rqstp; |
258 | int error = 0; | ||
266 | 259 | ||
267 | mutex_lock(&nlmsvc_mutex); | 260 | mutex_lock(&nlmsvc_mutex); |
268 | /* | 261 | /* |
269 | * Check whether we're already up and running. | 262 | * Check whether we're already up and running. |
270 | */ | 263 | */ |
271 | if (nlmsvc_pid) { | 264 | if (nlmsvc_serv) { |
272 | if (proto) | 265 | if (proto) |
273 | error = make_socks(nlmsvc_serv, proto); | 266 | error = make_socks(nlmsvc_serv, proto); |
274 | goto out; | 267 | goto out; |
@@ -295,13 +288,28 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */ | |||
295 | /* | 288 | /* |
296 | * Create the kernel thread and wait for it to start. | 289 | * Create the kernel thread and wait for it to start. |
297 | */ | 290 | */ |
298 | error = svc_create_thread(lockd, serv); | 291 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); |
299 | if (error) { | 292 | if (IS_ERR(rqstp)) { |
293 | error = PTR_ERR(rqstp); | ||
294 | printk(KERN_WARNING | ||
295 | "lockd_up: svc_rqst allocation failed, error=%d\n", | ||
296 | error); | ||
297 | goto destroy_and_out; | ||
298 | } | ||
299 | |||
300 | svc_sock_update_bufs(serv); | ||
301 | nlmsvc_serv = rqstp->rq_server; | ||
302 | |||
303 | nlmsvc_task = kthread_run(lockd, rqstp, serv->sv_name); | ||
304 | if (IS_ERR(nlmsvc_task)) { | ||
305 | error = PTR_ERR(nlmsvc_task); | ||
306 | nlmsvc_task = NULL; | ||
307 | nlmsvc_serv = NULL; | ||
300 | printk(KERN_WARNING | 308 | printk(KERN_WARNING |
301 | "lockd_up: create thread failed, error=%d\n", error); | 309 | "lockd_up: kthread_run failed, error=%d\n", error); |
310 | svc_exit_thread(rqstp); | ||
302 | goto destroy_and_out; | 311 | goto destroy_and_out; |
303 | } | 312 | } |
304 | wait_for_completion(&lockd_start_done); | ||
305 | 313 | ||
306 | /* | 314 | /* |
307 | * Note: svc_serv structures have an initial use count of 1, | 315 | * Note: svc_serv structures have an initial use count of 1, |
@@ -323,42 +331,28 @@ EXPORT_SYMBOL(lockd_up); | |||
323 | void | 331 | void |
324 | lockd_down(void) | 332 | lockd_down(void) |
325 | { | 333 | { |
326 | static int warned; | ||
327 | |||
328 | mutex_lock(&nlmsvc_mutex); | 334 | mutex_lock(&nlmsvc_mutex); |
329 | if (nlmsvc_users) { | 335 | if (nlmsvc_users) { |
330 | if (--nlmsvc_users) | 336 | if (--nlmsvc_users) |
331 | goto out; | 337 | goto out; |
332 | } else | 338 | } else { |
333 | printk(KERN_WARNING "lockd_down: no users! pid=%d\n", nlmsvc_pid); | 339 | printk(KERN_ERR "lockd_down: no users! task=%p\n", |
334 | 340 | nlmsvc_task); | |
335 | if (!nlmsvc_pid) { | 341 | BUG(); |
336 | if (warned++ == 0) | ||
337 | printk(KERN_WARNING "lockd_down: no lockd running.\n"); | ||
338 | goto out; | ||
339 | } | 342 | } |
340 | warned = 0; | ||
341 | 343 | ||
342 | kill_proc(nlmsvc_pid, SIGKILL, 1); | 344 | if (!nlmsvc_task) { |
343 | /* | 345 | printk(KERN_ERR "lockd_down: no lockd running.\n"); |
344 | * Wait for the lockd process to exit, but since we're holding | 346 | BUG(); |
345 | * the lockd semaphore, we can't wait around forever ... | ||
346 | */ | ||
347 | clear_thread_flag(TIF_SIGPENDING); | ||
348 | interruptible_sleep_on_timeout(&lockd_exit, HZ); | ||
349 | if (nlmsvc_pid) { | ||
350 | printk(KERN_WARNING | ||
351 | "lockd_down: lockd failed to exit, clearing pid\n"); | ||
352 | nlmsvc_pid = 0; | ||
353 | } | 347 | } |
354 | spin_lock_irq(¤t->sighand->siglock); | 348 | kthread_stop(nlmsvc_task); |
355 | recalc_sigpending(); | ||
356 | spin_unlock_irq(¤t->sighand->siglock); | ||
357 | out: | 349 | out: |
358 | mutex_unlock(&nlmsvc_mutex); | 350 | mutex_unlock(&nlmsvc_mutex); |
359 | } | 351 | } |
360 | EXPORT_SYMBOL(lockd_down); | 352 | EXPORT_SYMBOL(lockd_down); |
361 | 353 | ||
354 | #ifdef CONFIG_SYSCTL | ||
355 | |||
362 | /* | 356 | /* |
363 | * Sysctl parameters (same as module parameters, different interface). | 357 | * Sysctl parameters (same as module parameters, different interface). |
364 | */ | 358 | */ |
@@ -443,6 +437,8 @@ static ctl_table nlm_sysctl_root[] = { | |||
443 | { .ctl_name = 0 } | 437 | { .ctl_name = 0 } |
444 | }; | 438 | }; |
445 | 439 | ||
440 | #endif /* CONFIG_SYSCTL */ | ||
441 | |||
446 | /* | 442 | /* |
447 | * Module (and sysfs) parameters. | 443 | * Module (and sysfs) parameters. |
448 | */ | 444 | */ |
@@ -516,15 +512,21 @@ module_param(nsm_use_hostnames, bool, 0644); | |||
516 | 512 | ||
517 | static int __init init_nlm(void) | 513 | static int __init init_nlm(void) |
518 | { | 514 | { |
515 | #ifdef CONFIG_SYSCTL | ||
519 | nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); | 516 | nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); |
520 | return nlm_sysctl_table ? 0 : -ENOMEM; | 517 | return nlm_sysctl_table ? 0 : -ENOMEM; |
518 | #else | ||
519 | return 0; | ||
520 | #endif | ||
521 | } | 521 | } |
522 | 522 | ||
523 | static void __exit exit_nlm(void) | 523 | static void __exit exit_nlm(void) |
524 | { | 524 | { |
525 | /* FIXME: delete all NLM clients */ | 525 | /* FIXME: delete all NLM clients */ |
526 | nlm_shutdown_hosts(); | 526 | nlm_shutdown_hosts(); |
527 | #ifdef CONFIG_SYSCTL | ||
527 | unregister_sysctl_table(nlm_sysctl_table); | 528 | unregister_sysctl_table(nlm_sysctl_table); |
529 | #endif | ||
528 | } | 530 | } |
529 | 531 | ||
530 | module_init(init_nlm); | 532 | module_init(init_nlm); |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index fe9bdb4a220c..4d81553d2948 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/sunrpc/svc.h> | 29 | #include <linux/sunrpc/svc.h> |
30 | #include <linux/lockd/nlm.h> | 30 | #include <linux/lockd/nlm.h> |
31 | #include <linux/lockd/lockd.h> | 31 | #include <linux/lockd/lockd.h> |
32 | #include <linux/kthread.h> | ||
32 | 33 | ||
33 | #define NLMDBG_FACILITY NLMDBG_SVCLOCK | 34 | #define NLMDBG_FACILITY NLMDBG_SVCLOCK |
34 | 35 | ||
@@ -226,8 +227,7 @@ failed: | |||
226 | } | 227 | } |
227 | 228 | ||
228 | /* | 229 | /* |
229 | * Delete a block. If the lock was cancelled or the grant callback | 230 | * Delete a block. |
230 | * failed, unlock is set to 1. | ||
231 | * It is the caller's responsibility to check whether the file | 231 | * It is the caller's responsibility to check whether the file |
232 | * can be closed hereafter. | 232 | * can be closed hereafter. |
233 | */ | 233 | */ |
@@ -632,7 +632,7 @@ nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf, | |||
632 | block->b_flags |= B_TIMED_OUT; | 632 | block->b_flags |= B_TIMED_OUT; |
633 | if (conf) { | 633 | if (conf) { |
634 | if (block->b_fl) | 634 | if (block->b_fl) |
635 | locks_copy_lock(block->b_fl, conf); | 635 | __locks_copy_lock(block->b_fl, conf); |
636 | } | 636 | } |
637 | } | 637 | } |
638 | 638 | ||
@@ -887,7 +887,7 @@ nlmsvc_retry_blocked(void) | |||
887 | unsigned long timeout = MAX_SCHEDULE_TIMEOUT; | 887 | unsigned long timeout = MAX_SCHEDULE_TIMEOUT; |
888 | struct nlm_block *block; | 888 | struct nlm_block *block; |
889 | 889 | ||
890 | while (!list_empty(&nlm_blocked)) { | 890 | while (!list_empty(&nlm_blocked) && !kthread_should_stop()) { |
891 | block = list_entry(nlm_blocked.next, struct nlm_block, b_list); | 891 | block = list_entry(nlm_blocked.next, struct nlm_block, b_list); |
892 | 892 | ||
893 | if (block->b_when == NLM_NEVER) | 893 | if (block->b_when == NLM_NEVER) |
diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c index 068886de4dda..b0ae07008700 100644 --- a/fs/lockd/svcshare.c +++ b/fs/lockd/svcshare.c | |||
@@ -71,7 +71,8 @@ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, | |||
71 | struct nlm_share *share, **shpp; | 71 | struct nlm_share *share, **shpp; |
72 | struct xdr_netobj *oh = &argp->lock.oh; | 72 | struct xdr_netobj *oh = &argp->lock.oh; |
73 | 73 | ||
74 | for (shpp = &file->f_shares; (share = *shpp) != 0; shpp = &share->s_next) { | 74 | for (shpp = &file->f_shares; (share = *shpp) != NULL; |
75 | shpp = &share->s_next) { | ||
75 | if (share->s_host == host && nlm_cmp_owner(share, oh)) { | 76 | if (share->s_host == host && nlm_cmp_owner(share, oh)) { |
76 | *shpp = share->s_next; | 77 | *shpp = share->s_next; |
77 | kfree(share); | 78 | kfree(share); |
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index dbbefbcd6712..d1c48b539df8 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/lockd/lockd.h> | 18 | #include <linux/lockd/lockd.h> |
19 | #include <linux/lockd/share.h> | 19 | #include <linux/lockd/share.h> |
20 | #include <linux/lockd/sm_inter.h> | 20 | #include <linux/lockd/sm_inter.h> |
21 | #include <linux/module.h> | ||
22 | #include <linux/mount.h> | ||
21 | 23 | ||
22 | #define NLMDBG_FACILITY NLMDBG_SVCSUBS | 24 | #define NLMDBG_FACILITY NLMDBG_SVCSUBS |
23 | 25 | ||
@@ -194,6 +196,12 @@ again: | |||
194 | return 0; | 196 | return 0; |
195 | } | 197 | } |
196 | 198 | ||
199 | static int | ||
200 | nlmsvc_always_match(void *dummy1, struct nlm_host *dummy2) | ||
201 | { | ||
202 | return 1; | ||
203 | } | ||
204 | |||
197 | /* | 205 | /* |
198 | * Inspect a single file | 206 | * Inspect a single file |
199 | */ | 207 | */ |
@@ -230,7 +238,8 @@ nlm_file_inuse(struct nlm_file *file) | |||
230 | * Loop over all files in the file table. | 238 | * Loop over all files in the file table. |
231 | */ | 239 | */ |
232 | static int | 240 | static int |
233 | nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match) | 241 | nlm_traverse_files(void *data, nlm_host_match_fn_t match, |
242 | int (*is_failover_file)(void *data, struct nlm_file *file)) | ||
234 | { | 243 | { |
235 | struct hlist_node *pos, *next; | 244 | struct hlist_node *pos, *next; |
236 | struct nlm_file *file; | 245 | struct nlm_file *file; |
@@ -239,12 +248,14 @@ nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match) | |||
239 | mutex_lock(&nlm_file_mutex); | 248 | mutex_lock(&nlm_file_mutex); |
240 | for (i = 0; i < FILE_NRHASH; i++) { | 249 | for (i = 0; i < FILE_NRHASH; i++) { |
241 | hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) { | 250 | hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) { |
251 | if (is_failover_file && !is_failover_file(data, file)) | ||
252 | continue; | ||
242 | file->f_count++; | 253 | file->f_count++; |
243 | mutex_unlock(&nlm_file_mutex); | 254 | mutex_unlock(&nlm_file_mutex); |
244 | 255 | ||
245 | /* Traverse locks, blocks and shares of this file | 256 | /* Traverse locks, blocks and shares of this file |
246 | * and update file->f_locks count */ | 257 | * and update file->f_locks count */ |
247 | if (nlm_inspect_file(host, file, match)) | 258 | if (nlm_inspect_file(data, file, match)) |
248 | ret = 1; | 259 | ret = 1; |
249 | 260 | ||
250 | mutex_lock(&nlm_file_mutex); | 261 | mutex_lock(&nlm_file_mutex); |
@@ -303,21 +314,27 @@ nlm_release_file(struct nlm_file *file) | |||
303 | * Used by nlmsvc_invalidate_all | 314 | * Used by nlmsvc_invalidate_all |
304 | */ | 315 | */ |
305 | static int | 316 | static int |
306 | nlmsvc_mark_host(struct nlm_host *host, struct nlm_host *dummy) | 317 | nlmsvc_mark_host(void *data, struct nlm_host *dummy) |
307 | { | 318 | { |
319 | struct nlm_host *host = data; | ||
320 | |||
308 | host->h_inuse = 1; | 321 | host->h_inuse = 1; |
309 | return 0; | 322 | return 0; |
310 | } | 323 | } |
311 | 324 | ||
312 | static int | 325 | static int |
313 | nlmsvc_same_host(struct nlm_host *host, struct nlm_host *other) | 326 | nlmsvc_same_host(void *data, struct nlm_host *other) |
314 | { | 327 | { |
328 | struct nlm_host *host = data; | ||
329 | |||
315 | return host == other; | 330 | return host == other; |
316 | } | 331 | } |
317 | 332 | ||
318 | static int | 333 | static int |
319 | nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy) | 334 | nlmsvc_is_client(void *data, struct nlm_host *dummy) |
320 | { | 335 | { |
336 | struct nlm_host *host = data; | ||
337 | |||
321 | if (host->h_server) { | 338 | if (host->h_server) { |
322 | /* we are destroying locks even though the client | 339 | /* we are destroying locks even though the client |
323 | * hasn't asked us too, so don't unmonitor the | 340 | * hasn't asked us too, so don't unmonitor the |
@@ -337,7 +354,7 @@ void | |||
337 | nlmsvc_mark_resources(void) | 354 | nlmsvc_mark_resources(void) |
338 | { | 355 | { |
339 | dprintk("lockd: nlmsvc_mark_resources\n"); | 356 | dprintk("lockd: nlmsvc_mark_resources\n"); |
340 | nlm_traverse_files(NULL, nlmsvc_mark_host); | 357 | nlm_traverse_files(NULL, nlmsvc_mark_host, NULL); |
341 | } | 358 | } |
342 | 359 | ||
343 | /* | 360 | /* |
@@ -348,7 +365,7 @@ nlmsvc_free_host_resources(struct nlm_host *host) | |||
348 | { | 365 | { |
349 | dprintk("lockd: nlmsvc_free_host_resources\n"); | 366 | dprintk("lockd: nlmsvc_free_host_resources\n"); |
350 | 367 | ||
351 | if (nlm_traverse_files(host, nlmsvc_same_host)) { | 368 | if (nlm_traverse_files(host, nlmsvc_same_host, NULL)) { |
352 | printk(KERN_WARNING | 369 | printk(KERN_WARNING |
353 | "lockd: couldn't remove all locks held by %s\n", | 370 | "lockd: couldn't remove all locks held by %s\n", |
354 | host->h_name); | 371 | host->h_name); |
@@ -368,5 +385,41 @@ nlmsvc_invalidate_all(void) | |||
368 | * turn, which is about as inefficient as it gets. | 385 | * turn, which is about as inefficient as it gets. |
369 | * Now we just do it once in nlm_traverse_files. | 386 | * Now we just do it once in nlm_traverse_files. |
370 | */ | 387 | */ |
371 | nlm_traverse_files(NULL, nlmsvc_is_client); | 388 | nlm_traverse_files(NULL, nlmsvc_is_client, NULL); |
389 | } | ||
390 | |||
391 | static int | ||
392 | nlmsvc_match_sb(void *datap, struct nlm_file *file) | ||
393 | { | ||
394 | struct super_block *sb = datap; | ||
395 | |||
396 | return sb == file->f_file->f_path.mnt->mnt_sb; | ||
397 | } | ||
398 | |||
399 | int | ||
400 | nlmsvc_unlock_all_by_sb(struct super_block *sb) | ||
401 | { | ||
402 | int ret; | ||
403 | |||
404 | ret = nlm_traverse_files(sb, nlmsvc_always_match, nlmsvc_match_sb); | ||
405 | return ret ? -EIO : 0; | ||
406 | } | ||
407 | EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb); | ||
408 | |||
409 | static int | ||
410 | nlmsvc_match_ip(void *datap, struct nlm_host *host) | ||
411 | { | ||
412 | __be32 *server_addr = datap; | ||
413 | |||
414 | return host->h_saddr.sin_addr.s_addr == *server_addr; | ||
415 | } | ||
416 | |||
417 | int | ||
418 | nlmsvc_unlock_all_by_ip(__be32 server_addr) | ||
419 | { | ||
420 | int ret; | ||
421 | ret = nlm_traverse_files(&server_addr, nlmsvc_match_ip, NULL); | ||
422 | return ret ? -EIO : 0; | ||
423 | |||
372 | } | 424 | } |
425 | EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_ip); | ||
diff --git a/fs/locks.c b/fs/locks.c index 592faadbcec1..44d9a6a7ec50 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -224,7 +224,7 @@ static void locks_copy_private(struct file_lock *new, struct file_lock *fl) | |||
224 | /* | 224 | /* |
225 | * Initialize a new lock from an existing file_lock structure. | 225 | * Initialize a new lock from an existing file_lock structure. |
226 | */ | 226 | */ |
227 | static void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl) | 227 | void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl) |
228 | { | 228 | { |
229 | new->fl_owner = fl->fl_owner; | 229 | new->fl_owner = fl->fl_owner; |
230 | new->fl_pid = fl->fl_pid; | 230 | new->fl_pid = fl->fl_pid; |
@@ -236,6 +236,7 @@ static void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl) | |||
236 | new->fl_ops = NULL; | 236 | new->fl_ops = NULL; |
237 | new->fl_lmops = NULL; | 237 | new->fl_lmops = NULL; |
238 | } | 238 | } |
239 | EXPORT_SYMBOL(__locks_copy_lock); | ||
239 | 240 | ||
240 | void locks_copy_lock(struct file_lock *new, struct file_lock *fl) | 241 | void locks_copy_lock(struct file_lock *new, struct file_lock *fl) |
241 | { | 242 | { |
@@ -833,7 +834,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
833 | if (!posix_locks_conflict(request, fl)) | 834 | if (!posix_locks_conflict(request, fl)) |
834 | continue; | 835 | continue; |
835 | if (conflock) | 836 | if (conflock) |
836 | locks_copy_lock(conflock, fl); | 837 | __locks_copy_lock(conflock, fl); |
837 | error = -EAGAIN; | 838 | error = -EAGAIN; |
838 | if (!(request->fl_flags & FL_SLEEP)) | 839 | if (!(request->fl_flags & FL_SLEEP)) |
839 | goto out; | 840 | goto out; |
@@ -1367,18 +1368,20 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1367 | 1368 | ||
1368 | lease = *flp; | 1369 | lease = *flp; |
1369 | 1370 | ||
1370 | error = -EAGAIN; | 1371 | if (arg != F_UNLCK) { |
1371 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) | 1372 | error = -ENOMEM; |
1372 | goto out; | 1373 | new_fl = locks_alloc_lock(); |
1373 | if ((arg == F_WRLCK) | 1374 | if (new_fl == NULL) |
1374 | && ((atomic_read(&dentry->d_count) > 1) | 1375 | goto out; |
1375 | || (atomic_read(&inode->i_count) > 1))) | ||
1376 | goto out; | ||
1377 | 1376 | ||
1378 | error = -ENOMEM; | 1377 | error = -EAGAIN; |
1379 | new_fl = locks_alloc_lock(); | 1378 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) |
1380 | if (new_fl == NULL) | 1379 | goto out; |
1381 | goto out; | 1380 | if ((arg == F_WRLCK) |
1381 | && ((atomic_read(&dentry->d_count) > 1) | ||
1382 | || (atomic_read(&inode->i_count) > 1))) | ||
1383 | goto out; | ||
1384 | } | ||
1382 | 1385 | ||
1383 | /* | 1386 | /* |
1384 | * At this point, we know that if there is an exclusive | 1387 | * At this point, we know that if there is an exclusive |
@@ -1404,6 +1407,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1404 | rdlease_count++; | 1407 | rdlease_count++; |
1405 | } | 1408 | } |
1406 | 1409 | ||
1410 | error = -EAGAIN; | ||
1407 | if ((arg == F_RDLCK && (wrlease_count > 0)) || | 1411 | if ((arg == F_RDLCK && (wrlease_count > 0)) || |
1408 | (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0))) | 1412 | (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0))) |
1409 | goto out; | 1413 | goto out; |
@@ -1490,8 +1494,7 @@ EXPORT_SYMBOL_GPL(vfs_setlease); | |||
1490 | int fcntl_setlease(unsigned int fd, struct file *filp, long arg) | 1494 | int fcntl_setlease(unsigned int fd, struct file *filp, long arg) |
1491 | { | 1495 | { |
1492 | struct file_lock fl, *flp = &fl; | 1496 | struct file_lock fl, *flp = &fl; |
1493 | struct dentry *dentry = filp->f_path.dentry; | 1497 | struct inode *inode = filp->f_path.dentry->d_inode; |
1494 | struct inode *inode = dentry->d_inode; | ||
1495 | int error; | 1498 | int error; |
1496 | 1499 | ||
1497 | locks_init_lock(&fl); | 1500 | locks_init_lock(&fl); |
diff --git a/fs/namespace.c b/fs/namespace.c index 678f7ce060f2..f48f98110c30 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/mount.h> | 27 | #include <linux/mount.h> |
28 | #include <linux/ramfs.h> | 28 | #include <linux/ramfs.h> |
29 | #include <linux/log2.h> | 29 | #include <linux/log2.h> |
30 | #include <linux/idr.h> | ||
30 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
31 | #include <asm/unistd.h> | 32 | #include <asm/unistd.h> |
32 | #include "pnode.h" | 33 | #include "pnode.h" |
@@ -39,6 +40,8 @@ | |||
39 | __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); | 40 | __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); |
40 | 41 | ||
41 | static int event; | 42 | static int event; |
43 | static DEFINE_IDA(mnt_id_ida); | ||
44 | static DEFINE_IDA(mnt_group_ida); | ||
42 | 45 | ||
43 | static struct list_head *mount_hashtable __read_mostly; | 46 | static struct list_head *mount_hashtable __read_mostly; |
44 | static struct kmem_cache *mnt_cache __read_mostly; | 47 | static struct kmem_cache *mnt_cache __read_mostly; |
@@ -58,10 +61,63 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) | |||
58 | 61 | ||
59 | #define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16) | 62 | #define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16) |
60 | 63 | ||
64 | /* allocation is serialized by namespace_sem */ | ||
65 | static int mnt_alloc_id(struct vfsmount *mnt) | ||
66 | { | ||
67 | int res; | ||
68 | |||
69 | retry: | ||
70 | ida_pre_get(&mnt_id_ida, GFP_KERNEL); | ||
71 | spin_lock(&vfsmount_lock); | ||
72 | res = ida_get_new(&mnt_id_ida, &mnt->mnt_id); | ||
73 | spin_unlock(&vfsmount_lock); | ||
74 | if (res == -EAGAIN) | ||
75 | goto retry; | ||
76 | |||
77 | return res; | ||
78 | } | ||
79 | |||
80 | static void mnt_free_id(struct vfsmount *mnt) | ||
81 | { | ||
82 | spin_lock(&vfsmount_lock); | ||
83 | ida_remove(&mnt_id_ida, mnt->mnt_id); | ||
84 | spin_unlock(&vfsmount_lock); | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * Allocate a new peer group ID | ||
89 | * | ||
90 | * mnt_group_ida is protected by namespace_sem | ||
91 | */ | ||
92 | static int mnt_alloc_group_id(struct vfsmount *mnt) | ||
93 | { | ||
94 | if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL)) | ||
95 | return -ENOMEM; | ||
96 | |||
97 | return ida_get_new_above(&mnt_group_ida, 1, &mnt->mnt_group_id); | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Release a peer group ID | ||
102 | */ | ||
103 | void mnt_release_group_id(struct vfsmount *mnt) | ||
104 | { | ||
105 | ida_remove(&mnt_group_ida, mnt->mnt_group_id); | ||
106 | mnt->mnt_group_id = 0; | ||
107 | } | ||
108 | |||
61 | struct vfsmount *alloc_vfsmnt(const char *name) | 109 | struct vfsmount *alloc_vfsmnt(const char *name) |
62 | { | 110 | { |
63 | struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); | 111 | struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); |
64 | if (mnt) { | 112 | if (mnt) { |
113 | int err; | ||
114 | |||
115 | err = mnt_alloc_id(mnt); | ||
116 | if (err) { | ||
117 | kmem_cache_free(mnt_cache, mnt); | ||
118 | return NULL; | ||
119 | } | ||
120 | |||
65 | atomic_set(&mnt->mnt_count, 1); | 121 | atomic_set(&mnt->mnt_count, 1); |
66 | INIT_LIST_HEAD(&mnt->mnt_hash); | 122 | INIT_LIST_HEAD(&mnt->mnt_hash); |
67 | INIT_LIST_HEAD(&mnt->mnt_child); | 123 | INIT_LIST_HEAD(&mnt->mnt_child); |
@@ -353,6 +409,7 @@ EXPORT_SYMBOL(simple_set_mnt); | |||
353 | void free_vfsmnt(struct vfsmount *mnt) | 409 | void free_vfsmnt(struct vfsmount *mnt) |
354 | { | 410 | { |
355 | kfree(mnt->mnt_devname); | 411 | kfree(mnt->mnt_devname); |
412 | mnt_free_id(mnt); | ||
356 | kmem_cache_free(mnt_cache, mnt); | 413 | kmem_cache_free(mnt_cache, mnt); |
357 | } | 414 | } |
358 | 415 | ||
@@ -499,6 +556,17 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, | |||
499 | struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname); | 556 | struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname); |
500 | 557 | ||
501 | if (mnt) { | 558 | if (mnt) { |
559 | if (flag & (CL_SLAVE | CL_PRIVATE)) | ||
560 | mnt->mnt_group_id = 0; /* not a peer of original */ | ||
561 | else | ||
562 | mnt->mnt_group_id = old->mnt_group_id; | ||
563 | |||
564 | if ((flag & CL_MAKE_SHARED) && !mnt->mnt_group_id) { | ||
565 | int err = mnt_alloc_group_id(mnt); | ||
566 | if (err) | ||
567 | goto out_free; | ||
568 | } | ||
569 | |||
502 | mnt->mnt_flags = old->mnt_flags; | 570 | mnt->mnt_flags = old->mnt_flags; |
503 | atomic_inc(&sb->s_active); | 571 | atomic_inc(&sb->s_active); |
504 | mnt->mnt_sb = sb; | 572 | mnt->mnt_sb = sb; |
@@ -528,6 +596,10 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, | |||
528 | } | 596 | } |
529 | } | 597 | } |
530 | return mnt; | 598 | return mnt; |
599 | |||
600 | out_free: | ||
601 | free_vfsmnt(mnt); | ||
602 | return NULL; | ||
531 | } | 603 | } |
532 | 604 | ||
533 | static inline void __mntput(struct vfsmount *mnt) | 605 | static inline void __mntput(struct vfsmount *mnt) |
@@ -652,20 +724,21 @@ void save_mount_options(struct super_block *sb, char *options) | |||
652 | } | 724 | } |
653 | EXPORT_SYMBOL(save_mount_options); | 725 | EXPORT_SYMBOL(save_mount_options); |
654 | 726 | ||
727 | #ifdef CONFIG_PROC_FS | ||
655 | /* iterator */ | 728 | /* iterator */ |
656 | static void *m_start(struct seq_file *m, loff_t *pos) | 729 | static void *m_start(struct seq_file *m, loff_t *pos) |
657 | { | 730 | { |
658 | struct mnt_namespace *n = m->private; | 731 | struct proc_mounts *p = m->private; |
659 | 732 | ||
660 | down_read(&namespace_sem); | 733 | down_read(&namespace_sem); |
661 | return seq_list_start(&n->list, *pos); | 734 | return seq_list_start(&p->ns->list, *pos); |
662 | } | 735 | } |
663 | 736 | ||
664 | static void *m_next(struct seq_file *m, void *v, loff_t *pos) | 737 | static void *m_next(struct seq_file *m, void *v, loff_t *pos) |
665 | { | 738 | { |
666 | struct mnt_namespace *n = m->private; | 739 | struct proc_mounts *p = m->private; |
667 | 740 | ||
668 | return seq_list_next(v, &n->list, pos); | 741 | return seq_list_next(v, &p->ns->list, pos); |
669 | } | 742 | } |
670 | 743 | ||
671 | static void m_stop(struct seq_file *m, void *v) | 744 | static void m_stop(struct seq_file *m, void *v) |
@@ -673,20 +746,30 @@ static void m_stop(struct seq_file *m, void *v) | |||
673 | up_read(&namespace_sem); | 746 | up_read(&namespace_sem); |
674 | } | 747 | } |
675 | 748 | ||
676 | static int show_vfsmnt(struct seq_file *m, void *v) | 749 | struct proc_fs_info { |
750 | int flag; | ||
751 | const char *str; | ||
752 | }; | ||
753 | |||
754 | static void show_sb_opts(struct seq_file *m, struct super_block *sb) | ||
677 | { | 755 | { |
678 | struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); | 756 | static const struct proc_fs_info fs_info[] = { |
679 | int err = 0; | ||
680 | static struct proc_fs_info { | ||
681 | int flag; | ||
682 | char *str; | ||
683 | } fs_info[] = { | ||
684 | { MS_SYNCHRONOUS, ",sync" }, | 757 | { MS_SYNCHRONOUS, ",sync" }, |
685 | { MS_DIRSYNC, ",dirsync" }, | 758 | { MS_DIRSYNC, ",dirsync" }, |
686 | { MS_MANDLOCK, ",mand" }, | 759 | { MS_MANDLOCK, ",mand" }, |
687 | { 0, NULL } | 760 | { 0, NULL } |
688 | }; | 761 | }; |
689 | static struct proc_fs_info mnt_info[] = { | 762 | const struct proc_fs_info *fs_infop; |
763 | |||
764 | for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { | ||
765 | if (sb->s_flags & fs_infop->flag) | ||
766 | seq_puts(m, fs_infop->str); | ||
767 | } | ||
768 | } | ||
769 | |||
770 | static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) | ||
771 | { | ||
772 | static const struct proc_fs_info mnt_info[] = { | ||
690 | { MNT_NOSUID, ",nosuid" }, | 773 | { MNT_NOSUID, ",nosuid" }, |
691 | { MNT_NODEV, ",nodev" }, | 774 | { MNT_NODEV, ",nodev" }, |
692 | { MNT_NOEXEC, ",noexec" }, | 775 | { MNT_NOEXEC, ",noexec" }, |
@@ -695,40 +778,108 @@ static int show_vfsmnt(struct seq_file *m, void *v) | |||
695 | { MNT_RELATIME, ",relatime" }, | 778 | { MNT_RELATIME, ",relatime" }, |
696 | { 0, NULL } | 779 | { 0, NULL } |
697 | }; | 780 | }; |
698 | struct proc_fs_info *fs_infop; | 781 | const struct proc_fs_info *fs_infop; |
782 | |||
783 | for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) { | ||
784 | if (mnt->mnt_flags & fs_infop->flag) | ||
785 | seq_puts(m, fs_infop->str); | ||
786 | } | ||
787 | } | ||
788 | |||
789 | static void show_type(struct seq_file *m, struct super_block *sb) | ||
790 | { | ||
791 | mangle(m, sb->s_type->name); | ||
792 | if (sb->s_subtype && sb->s_subtype[0]) { | ||
793 | seq_putc(m, '.'); | ||
794 | mangle(m, sb->s_subtype); | ||
795 | } | ||
796 | } | ||
797 | |||
798 | static int show_vfsmnt(struct seq_file *m, void *v) | ||
799 | { | ||
800 | struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); | ||
801 | int err = 0; | ||
699 | struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; | 802 | struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; |
700 | 803 | ||
701 | mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); | 804 | mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); |
702 | seq_putc(m, ' '); | 805 | seq_putc(m, ' '); |
703 | seq_path(m, &mnt_path, " \t\n\\"); | 806 | seq_path(m, &mnt_path, " \t\n\\"); |
704 | seq_putc(m, ' '); | 807 | seq_putc(m, ' '); |
705 | mangle(m, mnt->mnt_sb->s_type->name); | 808 | show_type(m, mnt->mnt_sb); |
706 | if (mnt->mnt_sb->s_subtype && mnt->mnt_sb->s_subtype[0]) { | ||
707 | seq_putc(m, '.'); | ||
708 | mangle(m, mnt->mnt_sb->s_subtype); | ||
709 | } | ||
710 | seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw"); | 809 | seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw"); |
711 | for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { | 810 | show_sb_opts(m, mnt->mnt_sb); |
712 | if (mnt->mnt_sb->s_flags & fs_infop->flag) | 811 | show_mnt_opts(m, mnt); |
713 | seq_puts(m, fs_infop->str); | ||
714 | } | ||
715 | for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) { | ||
716 | if (mnt->mnt_flags & fs_infop->flag) | ||
717 | seq_puts(m, fs_infop->str); | ||
718 | } | ||
719 | if (mnt->mnt_sb->s_op->show_options) | 812 | if (mnt->mnt_sb->s_op->show_options) |
720 | err = mnt->mnt_sb->s_op->show_options(m, mnt); | 813 | err = mnt->mnt_sb->s_op->show_options(m, mnt); |
721 | seq_puts(m, " 0 0\n"); | 814 | seq_puts(m, " 0 0\n"); |
722 | return err; | 815 | return err; |
723 | } | 816 | } |
724 | 817 | ||
725 | struct seq_operations mounts_op = { | 818 | const struct seq_operations mounts_op = { |
726 | .start = m_start, | 819 | .start = m_start, |
727 | .next = m_next, | 820 | .next = m_next, |
728 | .stop = m_stop, | 821 | .stop = m_stop, |
729 | .show = show_vfsmnt | 822 | .show = show_vfsmnt |
730 | }; | 823 | }; |
731 | 824 | ||
825 | static int show_mountinfo(struct seq_file *m, void *v) | ||
826 | { | ||
827 | struct proc_mounts *p = m->private; | ||
828 | struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); | ||
829 | struct super_block *sb = mnt->mnt_sb; | ||
830 | struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; | ||
831 | struct path root = p->root; | ||
832 | int err = 0; | ||
833 | |||
834 | seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id, | ||
835 | MAJOR(sb->s_dev), MINOR(sb->s_dev)); | ||
836 | seq_dentry(m, mnt->mnt_root, " \t\n\\"); | ||
837 | seq_putc(m, ' '); | ||
838 | seq_path_root(m, &mnt_path, &root, " \t\n\\"); | ||
839 | if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) { | ||
840 | /* | ||
841 | * Mountpoint is outside root, discard that one. Ugly, | ||
842 | * but less so than trying to do that in iterator in a | ||
843 | * race-free way (due to renames). | ||
844 | */ | ||
845 | return SEQ_SKIP; | ||
846 | } | ||
847 | seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw"); | ||
848 | show_mnt_opts(m, mnt); | ||
849 | |||
850 | /* Tagged fields ("foo:X" or "bar") */ | ||
851 | if (IS_MNT_SHARED(mnt)) | ||
852 | seq_printf(m, " shared:%i", mnt->mnt_group_id); | ||
853 | if (IS_MNT_SLAVE(mnt)) { | ||
854 | int master = mnt->mnt_master->mnt_group_id; | ||
855 | int dom = get_dominating_id(mnt, &p->root); | ||
856 | seq_printf(m, " master:%i", master); | ||
857 | if (dom && dom != master) | ||
858 | seq_printf(m, " propagate_from:%i", dom); | ||
859 | } | ||
860 | if (IS_MNT_UNBINDABLE(mnt)) | ||
861 | seq_puts(m, " unbindable"); | ||
862 | |||
863 | /* Filesystem specific data */ | ||
864 | seq_puts(m, " - "); | ||
865 | show_type(m, sb); | ||
866 | seq_putc(m, ' '); | ||
867 | mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); | ||
868 | seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw"); | ||
869 | show_sb_opts(m, sb); | ||
870 | if (sb->s_op->show_options) | ||
871 | err = sb->s_op->show_options(m, mnt); | ||
872 | seq_putc(m, '\n'); | ||
873 | return err; | ||
874 | } | ||
875 | |||
876 | const struct seq_operations mountinfo_op = { | ||
877 | .start = m_start, | ||
878 | .next = m_next, | ||
879 | .stop = m_stop, | ||
880 | .show = show_mountinfo, | ||
881 | }; | ||
882 | |||
732 | static int show_vfsstat(struct seq_file *m, void *v) | 883 | static int show_vfsstat(struct seq_file *m, void *v) |
733 | { | 884 | { |
734 | struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); | 885 | struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); |
@@ -749,7 +900,7 @@ static int show_vfsstat(struct seq_file *m, void *v) | |||
749 | 900 | ||
750 | /* file system type */ | 901 | /* file system type */ |
751 | seq_puts(m, "with fstype "); | 902 | seq_puts(m, "with fstype "); |
752 | mangle(m, mnt->mnt_sb->s_type->name); | 903 | show_type(m, mnt->mnt_sb); |
753 | 904 | ||
754 | /* optional statistics */ | 905 | /* optional statistics */ |
755 | if (mnt->mnt_sb->s_op->show_stats) { | 906 | if (mnt->mnt_sb->s_op->show_stats) { |
@@ -761,12 +912,13 @@ static int show_vfsstat(struct seq_file *m, void *v) | |||
761 | return err; | 912 | return err; |
762 | } | 913 | } |
763 | 914 | ||
764 | struct seq_operations mountstats_op = { | 915 | const struct seq_operations mountstats_op = { |
765 | .start = m_start, | 916 | .start = m_start, |
766 | .next = m_next, | 917 | .next = m_next, |
767 | .stop = m_stop, | 918 | .stop = m_stop, |
768 | .show = show_vfsstat, | 919 | .show = show_vfsstat, |
769 | }; | 920 | }; |
921 | #endif /* CONFIG_PROC_FS */ | ||
770 | 922 | ||
771 | /** | 923 | /** |
772 | * may_umount_tree - check if a mount tree is busy | 924 | * may_umount_tree - check if a mount tree is busy |
@@ -909,10 +1061,11 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
909 | * about for the moment. | 1061 | * about for the moment. |
910 | */ | 1062 | */ |
911 | 1063 | ||
912 | lock_kernel(); | 1064 | if (flags & MNT_FORCE && sb->s_op->umount_begin) { |
913 | if (sb->s_op->umount_begin) | 1065 | lock_kernel(); |
914 | sb->s_op->umount_begin(mnt, flags); | 1066 | sb->s_op->umount_begin(sb); |
915 | unlock_kernel(); | 1067 | unlock_kernel(); |
1068 | } | ||
916 | 1069 | ||
917 | /* | 1070 | /* |
918 | * No sense to grab the lock for this test, but test itself looks | 1071 | * No sense to grab the lock for this test, but test itself looks |
@@ -1091,23 +1244,50 @@ Enomem: | |||
1091 | struct vfsmount *collect_mounts(struct vfsmount *mnt, struct dentry *dentry) | 1244 | struct vfsmount *collect_mounts(struct vfsmount *mnt, struct dentry *dentry) |
1092 | { | 1245 | { |
1093 | struct vfsmount *tree; | 1246 | struct vfsmount *tree; |
1094 | down_read(&namespace_sem); | 1247 | down_write(&namespace_sem); |
1095 | tree = copy_tree(mnt, dentry, CL_COPY_ALL | CL_PRIVATE); | 1248 | tree = copy_tree(mnt, dentry, CL_COPY_ALL | CL_PRIVATE); |
1096 | up_read(&namespace_sem); | 1249 | up_write(&namespace_sem); |
1097 | return tree; | 1250 | return tree; |
1098 | } | 1251 | } |
1099 | 1252 | ||
1100 | void drop_collected_mounts(struct vfsmount *mnt) | 1253 | void drop_collected_mounts(struct vfsmount *mnt) |
1101 | { | 1254 | { |
1102 | LIST_HEAD(umount_list); | 1255 | LIST_HEAD(umount_list); |
1103 | down_read(&namespace_sem); | 1256 | down_write(&namespace_sem); |
1104 | spin_lock(&vfsmount_lock); | 1257 | spin_lock(&vfsmount_lock); |
1105 | umount_tree(mnt, 0, &umount_list); | 1258 | umount_tree(mnt, 0, &umount_list); |
1106 | spin_unlock(&vfsmount_lock); | 1259 | spin_unlock(&vfsmount_lock); |
1107 | up_read(&namespace_sem); | 1260 | up_write(&namespace_sem); |
1108 | release_mounts(&umount_list); | 1261 | release_mounts(&umount_list); |
1109 | } | 1262 | } |
1110 | 1263 | ||
1264 | static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end) | ||
1265 | { | ||
1266 | struct vfsmount *p; | ||
1267 | |||
1268 | for (p = mnt; p != end; p = next_mnt(p, mnt)) { | ||
1269 | if (p->mnt_group_id && !IS_MNT_SHARED(p)) | ||
1270 | mnt_release_group_id(p); | ||
1271 | } | ||
1272 | } | ||
1273 | |||
1274 | static int invent_group_ids(struct vfsmount *mnt, bool recurse) | ||
1275 | { | ||
1276 | struct vfsmount *p; | ||
1277 | |||
1278 | for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) { | ||
1279 | if (!p->mnt_group_id && !IS_MNT_SHARED(p)) { | ||
1280 | int err = mnt_alloc_group_id(p); | ||
1281 | if (err) { | ||
1282 | cleanup_group_ids(mnt, p); | ||
1283 | return err; | ||
1284 | } | ||
1285 | } | ||
1286 | } | ||
1287 | |||
1288 | return 0; | ||
1289 | } | ||
1290 | |||
1111 | /* | 1291 | /* |
1112 | * @source_mnt : mount tree to be attached | 1292 | * @source_mnt : mount tree to be attached |
1113 | * @nd : place the mount tree @source_mnt is attached | 1293 | * @nd : place the mount tree @source_mnt is attached |
@@ -1178,9 +1358,16 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, | |||
1178 | struct vfsmount *dest_mnt = path->mnt; | 1358 | struct vfsmount *dest_mnt = path->mnt; |
1179 | struct dentry *dest_dentry = path->dentry; | 1359 | struct dentry *dest_dentry = path->dentry; |
1180 | struct vfsmount *child, *p; | 1360 | struct vfsmount *child, *p; |
1361 | int err; | ||
1181 | 1362 | ||
1182 | if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list)) | 1363 | if (IS_MNT_SHARED(dest_mnt)) { |
1183 | return -EINVAL; | 1364 | err = invent_group_ids(source_mnt, true); |
1365 | if (err) | ||
1366 | goto out; | ||
1367 | } | ||
1368 | err = propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list); | ||
1369 | if (err) | ||
1370 | goto out_cleanup_ids; | ||
1184 | 1371 | ||
1185 | if (IS_MNT_SHARED(dest_mnt)) { | 1372 | if (IS_MNT_SHARED(dest_mnt)) { |
1186 | for (p = source_mnt; p; p = next_mnt(p, source_mnt)) | 1373 | for (p = source_mnt; p; p = next_mnt(p, source_mnt)) |
@@ -1203,34 +1390,40 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, | |||
1203 | } | 1390 | } |
1204 | spin_unlock(&vfsmount_lock); | 1391 | spin_unlock(&vfsmount_lock); |
1205 | return 0; | 1392 | return 0; |
1393 | |||
1394 | out_cleanup_ids: | ||
1395 | if (IS_MNT_SHARED(dest_mnt)) | ||
1396 | cleanup_group_ids(source_mnt, NULL); | ||
1397 | out: | ||
1398 | return err; | ||
1206 | } | 1399 | } |
1207 | 1400 | ||
1208 | static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) | 1401 | static int graft_tree(struct vfsmount *mnt, struct path *path) |
1209 | { | 1402 | { |
1210 | int err; | 1403 | int err; |
1211 | if (mnt->mnt_sb->s_flags & MS_NOUSER) | 1404 | if (mnt->mnt_sb->s_flags & MS_NOUSER) |
1212 | return -EINVAL; | 1405 | return -EINVAL; |
1213 | 1406 | ||
1214 | if (S_ISDIR(nd->path.dentry->d_inode->i_mode) != | 1407 | if (S_ISDIR(path->dentry->d_inode->i_mode) != |
1215 | S_ISDIR(mnt->mnt_root->d_inode->i_mode)) | 1408 | S_ISDIR(mnt->mnt_root->d_inode->i_mode)) |
1216 | return -ENOTDIR; | 1409 | return -ENOTDIR; |
1217 | 1410 | ||
1218 | err = -ENOENT; | 1411 | err = -ENOENT; |
1219 | mutex_lock(&nd->path.dentry->d_inode->i_mutex); | 1412 | mutex_lock(&path->dentry->d_inode->i_mutex); |
1220 | if (IS_DEADDIR(nd->path.dentry->d_inode)) | 1413 | if (IS_DEADDIR(path->dentry->d_inode)) |
1221 | goto out_unlock; | 1414 | goto out_unlock; |
1222 | 1415 | ||
1223 | err = security_sb_check_sb(mnt, nd); | 1416 | err = security_sb_check_sb(mnt, path); |
1224 | if (err) | 1417 | if (err) |
1225 | goto out_unlock; | 1418 | goto out_unlock; |
1226 | 1419 | ||
1227 | err = -ENOENT; | 1420 | err = -ENOENT; |
1228 | if (IS_ROOT(nd->path.dentry) || !d_unhashed(nd->path.dentry)) | 1421 | if (IS_ROOT(path->dentry) || !d_unhashed(path->dentry)) |
1229 | err = attach_recursive_mnt(mnt, &nd->path, NULL); | 1422 | err = attach_recursive_mnt(mnt, path, NULL); |
1230 | out_unlock: | 1423 | out_unlock: |
1231 | mutex_unlock(&nd->path.dentry->d_inode->i_mutex); | 1424 | mutex_unlock(&path->dentry->d_inode->i_mutex); |
1232 | if (!err) | 1425 | if (!err) |
1233 | security_sb_post_addmount(mnt, nd); | 1426 | security_sb_post_addmount(mnt, path); |
1234 | return err; | 1427 | return err; |
1235 | } | 1428 | } |
1236 | 1429 | ||
@@ -1243,6 +1436,7 @@ static noinline int do_change_type(struct nameidata *nd, int flag) | |||
1243 | struct vfsmount *m, *mnt = nd->path.mnt; | 1436 | struct vfsmount *m, *mnt = nd->path.mnt; |
1244 | int recurse = flag & MS_REC; | 1437 | int recurse = flag & MS_REC; |
1245 | int type = flag & ~MS_REC; | 1438 | int type = flag & ~MS_REC; |
1439 | int err = 0; | ||
1246 | 1440 | ||
1247 | if (!capable(CAP_SYS_ADMIN)) | 1441 | if (!capable(CAP_SYS_ADMIN)) |
1248 | return -EPERM; | 1442 | return -EPERM; |
@@ -1251,12 +1445,20 @@ static noinline int do_change_type(struct nameidata *nd, int flag) | |||
1251 | return -EINVAL; | 1445 | return -EINVAL; |
1252 | 1446 | ||
1253 | down_write(&namespace_sem); | 1447 | down_write(&namespace_sem); |
1448 | if (type == MS_SHARED) { | ||
1449 | err = invent_group_ids(mnt, recurse); | ||
1450 | if (err) | ||
1451 | goto out_unlock; | ||
1452 | } | ||
1453 | |||
1254 | spin_lock(&vfsmount_lock); | 1454 | spin_lock(&vfsmount_lock); |
1255 | for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL)) | 1455 | for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL)) |
1256 | change_mnt_propagation(m, type); | 1456 | change_mnt_propagation(m, type); |
1257 | spin_unlock(&vfsmount_lock); | 1457 | spin_unlock(&vfsmount_lock); |
1458 | |||
1459 | out_unlock: | ||
1258 | up_write(&namespace_sem); | 1460 | up_write(&namespace_sem); |
1259 | return 0; | 1461 | return err; |
1260 | } | 1462 | } |
1261 | 1463 | ||
1262 | /* | 1464 | /* |
@@ -1294,7 +1496,7 @@ static noinline int do_loopback(struct nameidata *nd, char *old_name, | |||
1294 | if (!mnt) | 1496 | if (!mnt) |
1295 | goto out; | 1497 | goto out; |
1296 | 1498 | ||
1297 | err = graft_tree(mnt, nd); | 1499 | err = graft_tree(mnt, &nd->path); |
1298 | if (err) { | 1500 | if (err) { |
1299 | LIST_HEAD(umount_list); | 1501 | LIST_HEAD(umount_list); |
1300 | spin_lock(&vfsmount_lock); | 1502 | spin_lock(&vfsmount_lock); |
@@ -1501,7 +1703,7 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, | |||
1501 | goto unlock; | 1703 | goto unlock; |
1502 | 1704 | ||
1503 | newmnt->mnt_flags = mnt_flags; | 1705 | newmnt->mnt_flags = mnt_flags; |
1504 | if ((err = graft_tree(newmnt, nd))) | 1706 | if ((err = graft_tree(newmnt, &nd->path))) |
1505 | goto unlock; | 1707 | goto unlock; |
1506 | 1708 | ||
1507 | if (fslist) /* add to the specified expiration list */ | 1709 | if (fslist) /* add to the specified expiration list */ |
@@ -1746,7 +1948,8 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, | |||
1746 | if (retval) | 1948 | if (retval) |
1747 | return retval; | 1949 | return retval; |
1748 | 1950 | ||
1749 | retval = security_sb_mount(dev_name, &nd, type_page, flags, data_page); | 1951 | retval = security_sb_mount(dev_name, &nd.path, |
1952 | type_page, flags, data_page); | ||
1750 | if (retval) | 1953 | if (retval) |
1751 | goto dput_out; | 1954 | goto dput_out; |
1752 | 1955 | ||
@@ -1986,15 +2189,13 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
1986 | const char __user * put_old) | 2189 | const char __user * put_old) |
1987 | { | 2190 | { |
1988 | struct vfsmount *tmp; | 2191 | struct vfsmount *tmp; |
1989 | struct nameidata new_nd, old_nd, user_nd; | 2192 | struct nameidata new_nd, old_nd; |
1990 | struct path parent_path, root_parent; | 2193 | struct path parent_path, root_parent, root; |
1991 | int error; | 2194 | int error; |
1992 | 2195 | ||
1993 | if (!capable(CAP_SYS_ADMIN)) | 2196 | if (!capable(CAP_SYS_ADMIN)) |
1994 | return -EPERM; | 2197 | return -EPERM; |
1995 | 2198 | ||
1996 | lock_kernel(); | ||
1997 | |||
1998 | error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, | 2199 | error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, |
1999 | &new_nd); | 2200 | &new_nd); |
2000 | if (error) | 2201 | if (error) |
@@ -2007,14 +2208,14 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
2007 | if (error) | 2208 | if (error) |
2008 | goto out1; | 2209 | goto out1; |
2009 | 2210 | ||
2010 | error = security_sb_pivotroot(&old_nd, &new_nd); | 2211 | error = security_sb_pivotroot(&old_nd.path, &new_nd.path); |
2011 | if (error) { | 2212 | if (error) { |
2012 | path_put(&old_nd.path); | 2213 | path_put(&old_nd.path); |
2013 | goto out1; | 2214 | goto out1; |
2014 | } | 2215 | } |
2015 | 2216 | ||
2016 | read_lock(¤t->fs->lock); | 2217 | read_lock(¤t->fs->lock); |
2017 | user_nd.path = current->fs->root; | 2218 | root = current->fs->root; |
2018 | path_get(¤t->fs->root); | 2219 | path_get(¤t->fs->root); |
2019 | read_unlock(¤t->fs->lock); | 2220 | read_unlock(¤t->fs->lock); |
2020 | down_write(&namespace_sem); | 2221 | down_write(&namespace_sem); |
@@ -2022,9 +2223,9 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
2022 | error = -EINVAL; | 2223 | error = -EINVAL; |
2023 | if (IS_MNT_SHARED(old_nd.path.mnt) || | 2224 | if (IS_MNT_SHARED(old_nd.path.mnt) || |
2024 | IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) || | 2225 | IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) || |
2025 | IS_MNT_SHARED(user_nd.path.mnt->mnt_parent)) | 2226 | IS_MNT_SHARED(root.mnt->mnt_parent)) |
2026 | goto out2; | 2227 | goto out2; |
2027 | if (!check_mnt(user_nd.path.mnt)) | 2228 | if (!check_mnt(root.mnt)) |
2028 | goto out2; | 2229 | goto out2; |
2029 | error = -ENOENT; | 2230 | error = -ENOENT; |
2030 | if (IS_DEADDIR(new_nd.path.dentry->d_inode)) | 2231 | if (IS_DEADDIR(new_nd.path.dentry->d_inode)) |
@@ -2034,13 +2235,13 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
2034 | if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry)) | 2235 | if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry)) |
2035 | goto out2; | 2236 | goto out2; |
2036 | error = -EBUSY; | 2237 | error = -EBUSY; |
2037 | if (new_nd.path.mnt == user_nd.path.mnt || | 2238 | if (new_nd.path.mnt == root.mnt || |
2038 | old_nd.path.mnt == user_nd.path.mnt) | 2239 | old_nd.path.mnt == root.mnt) |
2039 | goto out2; /* loop, on the same file system */ | 2240 | goto out2; /* loop, on the same file system */ |
2040 | error = -EINVAL; | 2241 | error = -EINVAL; |
2041 | if (user_nd.path.mnt->mnt_root != user_nd.path.dentry) | 2242 | if (root.mnt->mnt_root != root.dentry) |
2042 | goto out2; /* not a mountpoint */ | 2243 | goto out2; /* not a mountpoint */ |
2043 | if (user_nd.path.mnt->mnt_parent == user_nd.path.mnt) | 2244 | if (root.mnt->mnt_parent == root.mnt) |
2044 | goto out2; /* not attached */ | 2245 | goto out2; /* not attached */ |
2045 | if (new_nd.path.mnt->mnt_root != new_nd.path.dentry) | 2246 | if (new_nd.path.mnt->mnt_root != new_nd.path.dentry) |
2046 | goto out2; /* not a mountpoint */ | 2247 | goto out2; /* not a mountpoint */ |
@@ -2062,27 +2263,26 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
2062 | } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) | 2263 | } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) |
2063 | goto out3; | 2264 | goto out3; |
2064 | detach_mnt(new_nd.path.mnt, &parent_path); | 2265 | detach_mnt(new_nd.path.mnt, &parent_path); |
2065 | detach_mnt(user_nd.path.mnt, &root_parent); | 2266 | detach_mnt(root.mnt, &root_parent); |
2066 | /* mount old root on put_old */ | 2267 | /* mount old root on put_old */ |
2067 | attach_mnt(user_nd.path.mnt, &old_nd.path); | 2268 | attach_mnt(root.mnt, &old_nd.path); |
2068 | /* mount new_root on / */ | 2269 | /* mount new_root on / */ |
2069 | attach_mnt(new_nd.path.mnt, &root_parent); | 2270 | attach_mnt(new_nd.path.mnt, &root_parent); |
2070 | touch_mnt_namespace(current->nsproxy->mnt_ns); | 2271 | touch_mnt_namespace(current->nsproxy->mnt_ns); |
2071 | spin_unlock(&vfsmount_lock); | 2272 | spin_unlock(&vfsmount_lock); |
2072 | chroot_fs_refs(&user_nd.path, &new_nd.path); | 2273 | chroot_fs_refs(&root, &new_nd.path); |
2073 | security_sb_post_pivotroot(&user_nd, &new_nd); | 2274 | security_sb_post_pivotroot(&root, &new_nd.path); |
2074 | error = 0; | 2275 | error = 0; |
2075 | path_put(&root_parent); | 2276 | path_put(&root_parent); |
2076 | path_put(&parent_path); | 2277 | path_put(&parent_path); |
2077 | out2: | 2278 | out2: |
2078 | mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); | 2279 | mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); |
2079 | up_write(&namespace_sem); | 2280 | up_write(&namespace_sem); |
2080 | path_put(&user_nd.path); | 2281 | path_put(&root); |
2081 | path_put(&old_nd.path); | 2282 | path_put(&old_nd.path); |
2082 | out1: | 2283 | out1: |
2083 | path_put(&new_nd.path); | 2284 | path_put(&new_nd.path); |
2084 | out0: | 2285 | out0: |
2085 | unlock_kernel(); | ||
2086 | return error; | 2286 | return error; |
2087 | out3: | 2287 | out3: |
2088 | spin_unlock(&vfsmount_lock); | 2288 | spin_unlock(&vfsmount_lock); |
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index df0f41e09885..ac6170c594a3 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | obj-$(CONFIG_NFS_FS) += nfs.o | 5 | obj-$(CONFIG_NFS_FS) += nfs.o |
6 | 6 | ||
7 | nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ | 7 | nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ |
8 | pagelist.o proc.o read.o symlink.o unlink.o \ | 8 | direct.o pagelist.o proc.o read.o symlink.o unlink.o \ |
9 | write.o namespace.o mount_clnt.o | 9 | write.o namespace.o mount_clnt.o |
10 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o | 10 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o |
11 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o | 11 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o |
@@ -14,5 +14,4 @@ nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ | |||
14 | delegation.o idmap.o \ | 14 | delegation.o idmap.o \ |
15 | callback.o callback_xdr.o callback_proc.o \ | 15 | callback.o callback_xdr.o callback_proc.o \ |
16 | nfs4namespace.o | 16 | nfs4namespace.o |
17 | nfs-$(CONFIG_NFS_DIRECTIO) += direct.o | ||
18 | nfs-$(CONFIG_SYSCTL) += sysctl.o | 17 | nfs-$(CONFIG_SYSCTL) += sysctl.o |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 66648dd92d97..5606ae3d72d3 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/nfs_fs.h> | 15 | #include <linux/nfs_fs.h> |
16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
17 | #include <linux/freezer.h> | 17 | #include <linux/freezer.h> |
18 | #include <linux/kthread.h> | ||
18 | 19 | ||
19 | #include <net/inet_sock.h> | 20 | #include <net/inet_sock.h> |
20 | 21 | ||
@@ -27,9 +28,7 @@ | |||
27 | struct nfs_callback_data { | 28 | struct nfs_callback_data { |
28 | unsigned int users; | 29 | unsigned int users; |
29 | struct svc_serv *serv; | 30 | struct svc_serv *serv; |
30 | pid_t pid; | 31 | struct task_struct *task; |
31 | struct completion started; | ||
32 | struct completion stopped; | ||
33 | }; | 32 | }; |
34 | 33 | ||
35 | static struct nfs_callback_data nfs_callback_info; | 34 | static struct nfs_callback_data nfs_callback_info; |
@@ -57,48 +56,44 @@ module_param_call(callback_tcpport, param_set_port, param_get_int, | |||
57 | /* | 56 | /* |
58 | * This is the callback kernel thread. | 57 | * This is the callback kernel thread. |
59 | */ | 58 | */ |
60 | static void nfs_callback_svc(struct svc_rqst *rqstp) | 59 | static int |
60 | nfs_callback_svc(void *vrqstp) | ||
61 | { | 61 | { |
62 | int err; | 62 | int err, preverr = 0; |
63 | struct svc_rqst *rqstp = vrqstp; | ||
63 | 64 | ||
64 | __module_get(THIS_MODULE); | ||
65 | lock_kernel(); | ||
66 | |||
67 | nfs_callback_info.pid = current->pid; | ||
68 | daemonize("nfsv4-svc"); | ||
69 | /* Process request with signals blocked, but allow SIGKILL. */ | ||
70 | allow_signal(SIGKILL); | ||
71 | set_freezable(); | 65 | set_freezable(); |
72 | 66 | ||
73 | complete(&nfs_callback_info.started); | 67 | /* |
74 | 68 | * FIXME: do we really need to run this under the BKL? If so, please | |
75 | for(;;) { | 69 | * add a comment about what it's intended to protect. |
76 | if (signalled()) { | 70 | */ |
77 | if (nfs_callback_info.users == 0) | 71 | lock_kernel(); |
78 | break; | 72 | while (!kthread_should_stop()) { |
79 | flush_signals(current); | ||
80 | } | ||
81 | /* | 73 | /* |
82 | * Listen for a request on the socket | 74 | * Listen for a request on the socket |
83 | */ | 75 | */ |
84 | err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT); | 76 | err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT); |
85 | if (err == -EAGAIN || err == -EINTR) | 77 | if (err == -EAGAIN || err == -EINTR) { |
78 | preverr = err; | ||
86 | continue; | 79 | continue; |
80 | } | ||
87 | if (err < 0) { | 81 | if (err < 0) { |
88 | printk(KERN_WARNING | 82 | if (err != preverr) { |
89 | "%s: terminating on error %d\n", | 83 | printk(KERN_WARNING "%s: unexpected error " |
90 | __FUNCTION__, -err); | 84 | "from svc_recv (%d)\n", __func__, err); |
91 | break; | 85 | preverr = err; |
86 | } | ||
87 | schedule_timeout_uninterruptible(HZ); | ||
88 | continue; | ||
92 | } | 89 | } |
90 | preverr = err; | ||
93 | svc_process(rqstp); | 91 | svc_process(rqstp); |
94 | } | 92 | } |
95 | |||
96 | flush_signals(current); | ||
97 | svc_exit_thread(rqstp); | ||
98 | nfs_callback_info.pid = 0; | ||
99 | complete(&nfs_callback_info.stopped); | ||
100 | unlock_kernel(); | 93 | unlock_kernel(); |
101 | module_put_and_exit(0); | 94 | nfs_callback_info.task = NULL; |
95 | svc_exit_thread(rqstp); | ||
96 | return 0; | ||
102 | } | 97 | } |
103 | 98 | ||
104 | /* | 99 | /* |
@@ -107,14 +102,13 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) | |||
107 | int nfs_callback_up(void) | 102 | int nfs_callback_up(void) |
108 | { | 103 | { |
109 | struct svc_serv *serv = NULL; | 104 | struct svc_serv *serv = NULL; |
105 | struct svc_rqst *rqstp; | ||
110 | int ret = 0; | 106 | int ret = 0; |
111 | 107 | ||
112 | lock_kernel(); | 108 | lock_kernel(); |
113 | mutex_lock(&nfs_callback_mutex); | 109 | mutex_lock(&nfs_callback_mutex); |
114 | if (nfs_callback_info.users++ || nfs_callback_info.pid != 0) | 110 | if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) |
115 | goto out; | 111 | goto out; |
116 | init_completion(&nfs_callback_info.started); | ||
117 | init_completion(&nfs_callback_info.stopped); | ||
118 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); | 112 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); |
119 | ret = -ENOMEM; | 113 | ret = -ENOMEM; |
120 | if (!serv) | 114 | if (!serv) |
@@ -127,15 +121,28 @@ int nfs_callback_up(void) | |||
127 | nfs_callback_tcpport = ret; | 121 | nfs_callback_tcpport = ret; |
128 | dprintk("Callback port = 0x%x\n", nfs_callback_tcpport); | 122 | dprintk("Callback port = 0x%x\n", nfs_callback_tcpport); |
129 | 123 | ||
130 | ret = svc_create_thread(nfs_callback_svc, serv); | 124 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); |
131 | if (ret < 0) | 125 | if (IS_ERR(rqstp)) { |
126 | ret = PTR_ERR(rqstp); | ||
132 | goto out_err; | 127 | goto out_err; |
128 | } | ||
129 | |||
130 | svc_sock_update_bufs(serv); | ||
133 | nfs_callback_info.serv = serv; | 131 | nfs_callback_info.serv = serv; |
134 | wait_for_completion(&nfs_callback_info.started); | 132 | |
133 | nfs_callback_info.task = kthread_run(nfs_callback_svc, rqstp, | ||
134 | "nfsv4-svc"); | ||
135 | if (IS_ERR(nfs_callback_info.task)) { | ||
136 | ret = PTR_ERR(nfs_callback_info.task); | ||
137 | nfs_callback_info.serv = NULL; | ||
138 | nfs_callback_info.task = NULL; | ||
139 | svc_exit_thread(rqstp); | ||
140 | goto out_err; | ||
141 | } | ||
135 | out: | 142 | out: |
136 | /* | 143 | /* |
137 | * svc_create creates the svc_serv with sv_nrthreads == 1, and then | 144 | * svc_create creates the svc_serv with sv_nrthreads == 1, and then |
138 | * svc_create_thread increments that. So we need to call svc_destroy | 145 | * svc_prepare_thread increments that. So we need to call svc_destroy |
139 | * on both success and failure so that the refcount is 1 when the | 146 | * on both success and failure so that the refcount is 1 when the |
140 | * thread exits. | 147 | * thread exits. |
141 | */ | 148 | */ |
@@ -152,19 +159,15 @@ out_err: | |||
152 | } | 159 | } |
153 | 160 | ||
154 | /* | 161 | /* |
155 | * Kill the server process if it is not already up. | 162 | * Kill the server process if it is not already down. |
156 | */ | 163 | */ |
157 | void nfs_callback_down(void) | 164 | void nfs_callback_down(void) |
158 | { | 165 | { |
159 | lock_kernel(); | 166 | lock_kernel(); |
160 | mutex_lock(&nfs_callback_mutex); | 167 | mutex_lock(&nfs_callback_mutex); |
161 | nfs_callback_info.users--; | 168 | nfs_callback_info.users--; |
162 | do { | 169 | if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) |
163 | if (nfs_callback_info.users != 0 || nfs_callback_info.pid == 0) | 170 | kthread_stop(nfs_callback_info.task); |
164 | break; | ||
165 | if (kill_proc(nfs_callback_info.pid, SIGKILL, 1) < 0) | ||
166 | break; | ||
167 | } while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0); | ||
168 | mutex_unlock(&nfs_callback_mutex); | 171 | mutex_unlock(&nfs_callback_mutex); |
169 | unlock_kernel(); | 172 | unlock_kernel(); |
170 | } | 173 | } |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index c5c0175898f6..f2f3b284e6dd 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -112,6 +112,7 @@ struct nfs_client_initdata { | |||
112 | static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) | 112 | static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) |
113 | { | 113 | { |
114 | struct nfs_client *clp; | 114 | struct nfs_client *clp; |
115 | struct rpc_cred *cred; | ||
115 | 116 | ||
116 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) | 117 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) |
117 | goto error_0; | 118 | goto error_0; |
@@ -150,6 +151,9 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
150 | clp->cl_boot_time = CURRENT_TIME; | 151 | clp->cl_boot_time = CURRENT_TIME; |
151 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | 152 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; |
152 | #endif | 153 | #endif |
154 | cred = rpc_lookup_machine_cred(); | ||
155 | if (!IS_ERR(cred)) | ||
156 | clp->cl_machine_cred = cred; | ||
153 | 157 | ||
154 | return clp; | 158 | return clp; |
155 | 159 | ||
@@ -170,6 +174,8 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
170 | BUG_ON(!RB_EMPTY_ROOT(&clp->cl_state_owners)); | 174 | BUG_ON(!RB_EMPTY_ROOT(&clp->cl_state_owners)); |
171 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) | 175 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) |
172 | nfs_idmap_delete(clp); | 176 | nfs_idmap_delete(clp); |
177 | |||
178 | rpc_destroy_wait_queue(&clp->cl_rpcwaitq); | ||
173 | #endif | 179 | #endif |
174 | } | 180 | } |
175 | 181 | ||
@@ -189,6 +195,9 @@ static void nfs_free_client(struct nfs_client *clp) | |||
189 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | 195 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) |
190 | nfs_callback_down(); | 196 | nfs_callback_down(); |
191 | 197 | ||
198 | if (clp->cl_machine_cred != NULL) | ||
199 | put_rpccred(clp->cl_machine_cred); | ||
200 | |||
192 | kfree(clp->cl_hostname); | 201 | kfree(clp->cl_hostname); |
193 | kfree(clp); | 202 | kfree(clp); |
194 | 203 | ||
@@ -680,10 +689,22 @@ static int nfs_init_server(struct nfs_server *server, | |||
680 | if (error < 0) | 689 | if (error < 0) |
681 | goto error; | 690 | goto error; |
682 | 691 | ||
692 | server->port = data->nfs_server.port; | ||
693 | |||
683 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); | 694 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); |
684 | if (error < 0) | 695 | if (error < 0) |
685 | goto error; | 696 | goto error; |
686 | 697 | ||
698 | /* Preserve the values of mount_server-related mount options */ | ||
699 | if (data->mount_server.addrlen) { | ||
700 | memcpy(&server->mountd_address, &data->mount_server.address, | ||
701 | data->mount_server.addrlen); | ||
702 | server->mountd_addrlen = data->mount_server.addrlen; | ||
703 | } | ||
704 | server->mountd_version = data->mount_server.version; | ||
705 | server->mountd_port = data->mount_server.port; | ||
706 | server->mountd_protocol = data->mount_server.protocol; | ||
707 | |||
687 | server->namelen = data->namlen; | 708 | server->namelen = data->namlen; |
688 | /* Create a client RPC handle for the NFSv3 ACL management interface */ | 709 | /* Create a client RPC handle for the NFSv3 ACL management interface */ |
689 | nfs_init_server_aclclient(server); | 710 | nfs_init_server_aclclient(server); |
@@ -1062,6 +1083,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1062 | server->acdirmin = data->acdirmin * HZ; | 1083 | server->acdirmin = data->acdirmin * HZ; |
1063 | server->acdirmax = data->acdirmax * HZ; | 1084 | server->acdirmax = data->acdirmax * HZ; |
1064 | 1085 | ||
1086 | server->port = data->nfs_server.port; | ||
1087 | |||
1065 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); | 1088 | error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); |
1066 | 1089 | ||
1067 | error: | 1090 | error: |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index d9e30ac2798d..f288b3ecab4a 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1967,7 +1967,7 @@ force_lookup: | |||
1967 | if (!NFS_PROTO(inode)->access) | 1967 | if (!NFS_PROTO(inode)->access) |
1968 | goto out_notsup; | 1968 | goto out_notsup; |
1969 | 1969 | ||
1970 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); | 1970 | cred = rpc_lookup_cred(); |
1971 | if (!IS_ERR(cred)) { | 1971 | if (!IS_ERR(cred)) { |
1972 | res = nfs_do_access(inode, cred, mask); | 1972 | res = nfs_do_access(inode, cred, mask); |
1973 | put_rpccred(cred); | 1973 | put_rpccred(cred); |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 16844f98f50e..4757a2b326a1 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -229,14 +229,20 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq) | |||
229 | static void nfs_direct_read_result(struct rpc_task *task, void *calldata) | 229 | static void nfs_direct_read_result(struct rpc_task *task, void *calldata) |
230 | { | 230 | { |
231 | struct nfs_read_data *data = calldata; | 231 | struct nfs_read_data *data = calldata; |
232 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
233 | 232 | ||
234 | if (nfs_readpage_result(task, data) != 0) | 233 | nfs_readpage_result(task, data); |
235 | return; | 234 | } |
235 | |||
236 | static void nfs_direct_read_release(void *calldata) | ||
237 | { | ||
238 | |||
239 | struct nfs_read_data *data = calldata; | ||
240 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
241 | int status = data->task.tk_status; | ||
236 | 242 | ||
237 | spin_lock(&dreq->lock); | 243 | spin_lock(&dreq->lock); |
238 | if (unlikely(task->tk_status < 0)) { | 244 | if (unlikely(status < 0)) { |
239 | dreq->error = task->tk_status; | 245 | dreq->error = status; |
240 | spin_unlock(&dreq->lock); | 246 | spin_unlock(&dreq->lock); |
241 | } else { | 247 | } else { |
242 | dreq->count += data->res.count; | 248 | dreq->count += data->res.count; |
@@ -249,11 +255,12 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata) | |||
249 | 255 | ||
250 | if (put_dreq(dreq)) | 256 | if (put_dreq(dreq)) |
251 | nfs_direct_complete(dreq); | 257 | nfs_direct_complete(dreq); |
258 | nfs_readdata_release(calldata); | ||
252 | } | 259 | } |
253 | 260 | ||
254 | static const struct rpc_call_ops nfs_read_direct_ops = { | 261 | static const struct rpc_call_ops nfs_read_direct_ops = { |
255 | .rpc_call_done = nfs_direct_read_result, | 262 | .rpc_call_done = nfs_direct_read_result, |
256 | .rpc_release = nfs_readdata_release, | 263 | .rpc_release = nfs_direct_read_release, |
257 | }; | 264 | }; |
258 | 265 | ||
259 | /* | 266 | /* |
@@ -280,6 +287,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
280 | .rpc_client = NFS_CLIENT(inode), | 287 | .rpc_client = NFS_CLIENT(inode), |
281 | .rpc_message = &msg, | 288 | .rpc_message = &msg, |
282 | .callback_ops = &nfs_read_direct_ops, | 289 | .callback_ops = &nfs_read_direct_ops, |
290 | .workqueue = nfsiod_workqueue, | ||
283 | .flags = RPC_TASK_ASYNC, | 291 | .flags = RPC_TASK_ASYNC, |
284 | }; | 292 | }; |
285 | unsigned int pgbase; | 293 | unsigned int pgbase; |
@@ -323,7 +331,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
323 | data->inode = inode; | 331 | data->inode = inode; |
324 | data->cred = msg.rpc_cred; | 332 | data->cred = msg.rpc_cred; |
325 | data->args.fh = NFS_FH(inode); | 333 | data->args.fh = NFS_FH(inode); |
326 | data->args.context = ctx; | 334 | data->args.context = get_nfs_open_context(ctx); |
327 | data->args.offset = pos; | 335 | data->args.offset = pos; |
328 | data->args.pgbase = pgbase; | 336 | data->args.pgbase = pgbase; |
329 | data->args.pages = data->pagevec; | 337 | data->args.pages = data->pagevec; |
@@ -339,8 +347,9 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
339 | NFS_PROTO(inode)->read_setup(data, &msg); | 347 | NFS_PROTO(inode)->read_setup(data, &msg); |
340 | 348 | ||
341 | task = rpc_run_task(&task_setup_data); | 349 | task = rpc_run_task(&task_setup_data); |
342 | if (!IS_ERR(task)) | 350 | if (IS_ERR(task)) |
343 | rpc_put_task(task); | 351 | break; |
352 | rpc_put_task(task); | ||
344 | 353 | ||
345 | dprintk("NFS: %5u initiated direct read call " | 354 | dprintk("NFS: %5u initiated direct read call " |
346 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", | 355 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", |
@@ -446,6 +455,7 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
446 | struct rpc_task_setup task_setup_data = { | 455 | struct rpc_task_setup task_setup_data = { |
447 | .rpc_client = NFS_CLIENT(inode), | 456 | .rpc_client = NFS_CLIENT(inode), |
448 | .callback_ops = &nfs_write_direct_ops, | 457 | .callback_ops = &nfs_write_direct_ops, |
458 | .workqueue = nfsiod_workqueue, | ||
449 | .flags = RPC_TASK_ASYNC, | 459 | .flags = RPC_TASK_ASYNC, |
450 | }; | 460 | }; |
451 | 461 | ||
@@ -499,27 +509,34 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
499 | static void nfs_direct_commit_result(struct rpc_task *task, void *calldata) | 509 | static void nfs_direct_commit_result(struct rpc_task *task, void *calldata) |
500 | { | 510 | { |
501 | struct nfs_write_data *data = calldata; | 511 | struct nfs_write_data *data = calldata; |
502 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
503 | 512 | ||
504 | /* Call the NFS version-specific code */ | 513 | /* Call the NFS version-specific code */ |
505 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | 514 | NFS_PROTO(data->inode)->commit_done(task, data); |
506 | return; | 515 | } |
507 | if (unlikely(task->tk_status < 0)) { | 516 | |
517 | static void nfs_direct_commit_release(void *calldata) | ||
518 | { | ||
519 | struct nfs_write_data *data = calldata; | ||
520 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
521 | int status = data->task.tk_status; | ||
522 | |||
523 | if (status < 0) { | ||
508 | dprintk("NFS: %5u commit failed with error %d.\n", | 524 | dprintk("NFS: %5u commit failed with error %d.\n", |
509 | task->tk_pid, task->tk_status); | 525 | data->task.tk_pid, status); |
510 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 526 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
511 | } else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { | 527 | } else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { |
512 | dprintk("NFS: %5u commit verify failed\n", task->tk_pid); | 528 | dprintk("NFS: %5u commit verify failed\n", data->task.tk_pid); |
513 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 529 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
514 | } | 530 | } |
515 | 531 | ||
516 | dprintk("NFS: %5u commit returned %d\n", task->tk_pid, task->tk_status); | 532 | dprintk("NFS: %5u commit returned %d\n", data->task.tk_pid, status); |
517 | nfs_direct_write_complete(dreq, data->inode); | 533 | nfs_direct_write_complete(dreq, data->inode); |
534 | nfs_commitdata_release(calldata); | ||
518 | } | 535 | } |
519 | 536 | ||
520 | static const struct rpc_call_ops nfs_commit_direct_ops = { | 537 | static const struct rpc_call_ops nfs_commit_direct_ops = { |
521 | .rpc_call_done = nfs_direct_commit_result, | 538 | .rpc_call_done = nfs_direct_commit_result, |
522 | .rpc_release = nfs_commit_release, | 539 | .rpc_release = nfs_direct_commit_release, |
523 | }; | 540 | }; |
524 | 541 | ||
525 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | 542 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) |
@@ -537,6 +554,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
537 | .rpc_message = &msg, | 554 | .rpc_message = &msg, |
538 | .callback_ops = &nfs_commit_direct_ops, | 555 | .callback_ops = &nfs_commit_direct_ops, |
539 | .callback_data = data, | 556 | .callback_data = data, |
557 | .workqueue = nfsiod_workqueue, | ||
540 | .flags = RPC_TASK_ASYNC, | 558 | .flags = RPC_TASK_ASYNC, |
541 | }; | 559 | }; |
542 | 560 | ||
@@ -546,6 +564,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
546 | data->args.fh = NFS_FH(data->inode); | 564 | data->args.fh = NFS_FH(data->inode); |
547 | data->args.offset = 0; | 565 | data->args.offset = 0; |
548 | data->args.count = 0; | 566 | data->args.count = 0; |
567 | data->args.context = get_nfs_open_context(dreq->ctx); | ||
549 | data->res.count = 0; | 568 | data->res.count = 0; |
550 | data->res.fattr = &data->fattr; | 569 | data->res.fattr = &data->fattr; |
551 | data->res.verf = &data->verf; | 570 | data->res.verf = &data->verf; |
@@ -585,7 +604,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode | |||
585 | 604 | ||
586 | static void nfs_alloc_commit_data(struct nfs_direct_req *dreq) | 605 | static void nfs_alloc_commit_data(struct nfs_direct_req *dreq) |
587 | { | 606 | { |
588 | dreq->commit_data = nfs_commit_alloc(); | 607 | dreq->commit_data = nfs_commitdata_alloc(); |
589 | if (dreq->commit_data != NULL) | 608 | if (dreq->commit_data != NULL) |
590 | dreq->commit_data->req = (struct nfs_page *) dreq; | 609 | dreq->commit_data->req = (struct nfs_page *) dreq; |
591 | } | 610 | } |
@@ -606,11 +625,20 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode | |||
606 | static void nfs_direct_write_result(struct rpc_task *task, void *calldata) | 625 | static void nfs_direct_write_result(struct rpc_task *task, void *calldata) |
607 | { | 626 | { |
608 | struct nfs_write_data *data = calldata; | 627 | struct nfs_write_data *data = calldata; |
609 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
610 | int status = task->tk_status; | ||
611 | 628 | ||
612 | if (nfs_writeback_done(task, data) != 0) | 629 | if (nfs_writeback_done(task, data) != 0) |
613 | return; | 630 | return; |
631 | } | ||
632 | |||
633 | /* | ||
634 | * NB: Return the value of the first error return code. Subsequent | ||
635 | * errors after the first one are ignored. | ||
636 | */ | ||
637 | static void nfs_direct_write_release(void *calldata) | ||
638 | { | ||
639 | struct nfs_write_data *data = calldata; | ||
640 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
641 | int status = data->task.tk_status; | ||
614 | 642 | ||
615 | spin_lock(&dreq->lock); | 643 | spin_lock(&dreq->lock); |
616 | 644 | ||
@@ -632,23 +660,13 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata) | |||
632 | break; | 660 | break; |
633 | case NFS_ODIRECT_DO_COMMIT: | 661 | case NFS_ODIRECT_DO_COMMIT: |
634 | if (memcmp(&dreq->verf, &data->verf, sizeof(dreq->verf))) { | 662 | if (memcmp(&dreq->verf, &data->verf, sizeof(dreq->verf))) { |
635 | dprintk("NFS: %5u write verify failed\n", task->tk_pid); | 663 | dprintk("NFS: %5u write verify failed\n", data->task.tk_pid); |
636 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 664 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
637 | } | 665 | } |
638 | } | 666 | } |
639 | } | 667 | } |
640 | out_unlock: | 668 | out_unlock: |
641 | spin_unlock(&dreq->lock); | 669 | spin_unlock(&dreq->lock); |
642 | } | ||
643 | |||
644 | /* | ||
645 | * NB: Return the value of the first error return code. Subsequent | ||
646 | * errors after the first one are ignored. | ||
647 | */ | ||
648 | static void nfs_direct_write_release(void *calldata) | ||
649 | { | ||
650 | struct nfs_write_data *data = calldata; | ||
651 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
652 | 670 | ||
653 | if (put_dreq(dreq)) | 671 | if (put_dreq(dreq)) |
654 | nfs_direct_write_complete(dreq, data->inode); | 672 | nfs_direct_write_complete(dreq, data->inode); |
@@ -682,6 +700,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
682 | .rpc_client = NFS_CLIENT(inode), | 700 | .rpc_client = NFS_CLIENT(inode), |
683 | .rpc_message = &msg, | 701 | .rpc_message = &msg, |
684 | .callback_ops = &nfs_write_direct_ops, | 702 | .callback_ops = &nfs_write_direct_ops, |
703 | .workqueue = nfsiod_workqueue, | ||
685 | .flags = RPC_TASK_ASYNC, | 704 | .flags = RPC_TASK_ASYNC, |
686 | }; | 705 | }; |
687 | size_t wsize = NFS_SERVER(inode)->wsize; | 706 | size_t wsize = NFS_SERVER(inode)->wsize; |
@@ -728,7 +747,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
728 | data->inode = inode; | 747 | data->inode = inode; |
729 | data->cred = msg.rpc_cred; | 748 | data->cred = msg.rpc_cred; |
730 | data->args.fh = NFS_FH(inode); | 749 | data->args.fh = NFS_FH(inode); |
731 | data->args.context = ctx; | 750 | data->args.context = get_nfs_open_context(ctx); |
732 | data->args.offset = pos; | 751 | data->args.offset = pos; |
733 | data->args.pgbase = pgbase; | 752 | data->args.pgbase = pgbase; |
734 | data->args.pages = data->pagevec; | 753 | data->args.pages = data->pagevec; |
@@ -745,8 +764,9 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
745 | NFS_PROTO(inode)->write_setup(data, &msg); | 764 | NFS_PROTO(inode)->write_setup(data, &msg); |
746 | 765 | ||
747 | task = rpc_run_task(&task_setup_data); | 766 | task = rpc_run_task(&task_setup_data); |
748 | if (!IS_ERR(task)) | 767 | if (IS_ERR(task)) |
749 | rpc_put_task(task); | 768 | break; |
769 | rpc_put_task(task); | ||
750 | 770 | ||
751 | dprintk("NFS: %5u initiated direct write call " | 771 | dprintk("NFS: %5u initiated direct write call " |
752 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", | 772 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 5d2e9d9a4e28..3536b01164f9 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -238,10 +238,8 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov, | |||
238 | ssize_t result; | 238 | ssize_t result; |
239 | size_t count = iov_length(iov, nr_segs); | 239 | size_t count = iov_length(iov, nr_segs); |
240 | 240 | ||
241 | #ifdef CONFIG_NFS_DIRECTIO | ||
242 | if (iocb->ki_filp->f_flags & O_DIRECT) | 241 | if (iocb->ki_filp->f_flags & O_DIRECT) |
243 | return nfs_file_direct_read(iocb, iov, nr_segs, pos); | 242 | return nfs_file_direct_read(iocb, iov, nr_segs, pos); |
244 | #endif | ||
245 | 243 | ||
246 | dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n", | 244 | dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n", |
247 | dentry->d_parent->d_name.name, dentry->d_name.name, | 245 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -387,9 +385,7 @@ const struct address_space_operations nfs_file_aops = { | |||
387 | .write_end = nfs_write_end, | 385 | .write_end = nfs_write_end, |
388 | .invalidatepage = nfs_invalidate_page, | 386 | .invalidatepage = nfs_invalidate_page, |
389 | .releasepage = nfs_release_page, | 387 | .releasepage = nfs_release_page, |
390 | #ifdef CONFIG_NFS_DIRECTIO | ||
391 | .direct_IO = nfs_direct_IO, | 388 | .direct_IO = nfs_direct_IO, |
392 | #endif | ||
393 | .launder_page = nfs_launder_page, | 389 | .launder_page = nfs_launder_page, |
394 | }; | 390 | }; |
395 | 391 | ||
@@ -447,10 +443,8 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
447 | ssize_t result; | 443 | ssize_t result; |
448 | size_t count = iov_length(iov, nr_segs); | 444 | size_t count = iov_length(iov, nr_segs); |
449 | 445 | ||
450 | #ifdef CONFIG_NFS_DIRECTIO | ||
451 | if (iocb->ki_filp->f_flags & O_DIRECT) | 446 | if (iocb->ki_filp->f_flags & O_DIRECT) |
452 | return nfs_file_direct_write(iocb, iov, nr_segs, pos); | 447 | return nfs_file_direct_write(iocb, iov, nr_segs, pos); |
453 | #endif | ||
454 | 448 | ||
455 | dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n", | 449 | dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n", |
456 | dentry->d_parent->d_name.name, dentry->d_name.name, | 450 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -576,17 +570,9 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) | |||
576 | 570 | ||
577 | lock_kernel(); | 571 | lock_kernel(); |
578 | /* Use local locking if mounted with "-onolock" */ | 572 | /* Use local locking if mounted with "-onolock" */ |
579 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) { | 573 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) |
580 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); | 574 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); |
581 | /* If we were signalled we still need to ensure that | 575 | else |
582 | * we clean up any state on the server. We therefore | ||
583 | * record the lock call as having succeeded in order to | ||
584 | * ensure that locks_remove_posix() cleans it out when | ||
585 | * the process exits. | ||
586 | */ | ||
587 | if (status == -EINTR || status == -ERESTARTSYS) | ||
588 | do_vfs_lock(filp, fl); | ||
589 | } else | ||
590 | status = do_vfs_lock(filp, fl); | 576 | status = do_vfs_lock(filp, fl); |
591 | unlock_kernel(); | 577 | unlock_kernel(); |
592 | if (status < 0) | 578 | if (status < 0) |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6f88d7c77ac9..5cb3345eb694 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -523,8 +523,12 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) | |||
523 | 523 | ||
524 | static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait) | 524 | static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait) |
525 | { | 525 | { |
526 | struct inode *inode = ctx->path.dentry->d_inode; | 526 | struct inode *inode; |
527 | 527 | ||
528 | if (ctx == NULL) | ||
529 | return; | ||
530 | |||
531 | inode = ctx->path.dentry->d_inode; | ||
528 | if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) | 532 | if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) |
529 | return; | 533 | return; |
530 | list_del(&ctx->list); | 534 | list_del(&ctx->list); |
@@ -610,7 +614,7 @@ int nfs_open(struct inode *inode, struct file *filp) | |||
610 | struct nfs_open_context *ctx; | 614 | struct nfs_open_context *ctx; |
611 | struct rpc_cred *cred; | 615 | struct rpc_cred *cred; |
612 | 616 | ||
613 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); | 617 | cred = rpc_lookup_cred(); |
614 | if (IS_ERR(cred)) | 618 | if (IS_ERR(cred)) |
615 | return PTR_ERR(cred); | 619 | return PTR_ERR(cred); |
616 | ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred); | 620 | ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred); |
@@ -1218,6 +1222,36 @@ static void nfs_destroy_inodecache(void) | |||
1218 | kmem_cache_destroy(nfs_inode_cachep); | 1222 | kmem_cache_destroy(nfs_inode_cachep); |
1219 | } | 1223 | } |
1220 | 1224 | ||
1225 | struct workqueue_struct *nfsiod_workqueue; | ||
1226 | |||
1227 | /* | ||
1228 | * start up the nfsiod workqueue | ||
1229 | */ | ||
1230 | static int nfsiod_start(void) | ||
1231 | { | ||
1232 | struct workqueue_struct *wq; | ||
1233 | dprintk("RPC: creating workqueue nfsiod\n"); | ||
1234 | wq = create_singlethread_workqueue("nfsiod"); | ||
1235 | if (wq == NULL) | ||
1236 | return -ENOMEM; | ||
1237 | nfsiod_workqueue = wq; | ||
1238 | return 0; | ||
1239 | } | ||
1240 | |||
1241 | /* | ||
1242 | * Destroy the nfsiod workqueue | ||
1243 | */ | ||
1244 | static void nfsiod_stop(void) | ||
1245 | { | ||
1246 | struct workqueue_struct *wq; | ||
1247 | |||
1248 | wq = nfsiod_workqueue; | ||
1249 | if (wq == NULL) | ||
1250 | return; | ||
1251 | nfsiod_workqueue = NULL; | ||
1252 | destroy_workqueue(wq); | ||
1253 | } | ||
1254 | |||
1221 | /* | 1255 | /* |
1222 | * Initialize NFS | 1256 | * Initialize NFS |
1223 | */ | 1257 | */ |
@@ -1225,6 +1259,10 @@ static int __init init_nfs_fs(void) | |||
1225 | { | 1259 | { |
1226 | int err; | 1260 | int err; |
1227 | 1261 | ||
1262 | err = nfsiod_start(); | ||
1263 | if (err) | ||
1264 | goto out6; | ||
1265 | |||
1228 | err = nfs_fs_proc_init(); | 1266 | err = nfs_fs_proc_init(); |
1229 | if (err) | 1267 | if (err) |
1230 | goto out5; | 1268 | goto out5; |
@@ -1271,6 +1309,8 @@ out3: | |||
1271 | out4: | 1309 | out4: |
1272 | nfs_fs_proc_exit(); | 1310 | nfs_fs_proc_exit(); |
1273 | out5: | 1311 | out5: |
1312 | nfsiod_stop(); | ||
1313 | out6: | ||
1274 | return err; | 1314 | return err; |
1275 | } | 1315 | } |
1276 | 1316 | ||
@@ -1286,6 +1326,7 @@ static void __exit exit_nfs_fs(void) | |||
1286 | #endif | 1326 | #endif |
1287 | unregister_nfs_fs(); | 1327 | unregister_nfs_fs(); |
1288 | nfs_fs_proc_exit(); | 1328 | nfs_fs_proc_exit(); |
1329 | nfsiod_stop(); | ||
1289 | } | 1330 | } |
1290 | 1331 | ||
1291 | /* Not quite true; I just maintain it */ | 1332 | /* Not quite true; I just maintain it */ |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 931992763e68..04ae867dddba 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -46,9 +46,9 @@ struct nfs_parsed_mount_data { | |||
46 | struct sockaddr_storage address; | 46 | struct sockaddr_storage address; |
47 | size_t addrlen; | 47 | size_t addrlen; |
48 | char *hostname; | 48 | char *hostname; |
49 | unsigned int version; | 49 | u32 version; |
50 | unsigned short port; | 50 | unsigned short port; |
51 | int protocol; | 51 | unsigned short protocol; |
52 | } mount_server; | 52 | } mount_server; |
53 | 53 | ||
54 | struct { | 54 | struct { |
@@ -56,7 +56,8 @@ struct nfs_parsed_mount_data { | |||
56 | size_t addrlen; | 56 | size_t addrlen; |
57 | char *hostname; | 57 | char *hostname; |
58 | char *export_path; | 58 | char *export_path; |
59 | int protocol; | 59 | unsigned short port; |
60 | unsigned short protocol; | ||
60 | } nfs_server; | 61 | } nfs_server; |
61 | 62 | ||
62 | struct security_mnt_opts lsm_opts; | 63 | struct security_mnt_opts lsm_opts; |
@@ -115,13 +116,8 @@ extern void nfs_destroy_readpagecache(void); | |||
115 | extern int __init nfs_init_writepagecache(void); | 116 | extern int __init nfs_init_writepagecache(void); |
116 | extern void nfs_destroy_writepagecache(void); | 117 | extern void nfs_destroy_writepagecache(void); |
117 | 118 | ||
118 | #ifdef CONFIG_NFS_DIRECTIO | ||
119 | extern int __init nfs_init_directcache(void); | 119 | extern int __init nfs_init_directcache(void); |
120 | extern void nfs_destroy_directcache(void); | 120 | extern void nfs_destroy_directcache(void); |
121 | #else | ||
122 | #define nfs_init_directcache() (0) | ||
123 | #define nfs_destroy_directcache() do {} while(0) | ||
124 | #endif | ||
125 | 121 | ||
126 | /* nfs2xdr.c */ | 122 | /* nfs2xdr.c */ |
127 | extern int nfs_stat_to_errno(int); | 123 | extern int nfs_stat_to_errno(int); |
@@ -146,6 +142,7 @@ extern struct rpc_procinfo nfs4_procedures[]; | |||
146 | extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask); | 142 | extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask); |
147 | 143 | ||
148 | /* inode.c */ | 144 | /* inode.c */ |
145 | extern struct workqueue_struct *nfsiod_workqueue; | ||
149 | extern struct inode *nfs_alloc_inode(struct super_block *sb); | 146 | extern struct inode *nfs_alloc_inode(struct super_block *sb); |
150 | extern void nfs_destroy_inode(struct inode *); | 147 | extern void nfs_destroy_inode(struct inode *); |
151 | extern int nfs_write_inode(struct inode *,int); | 148 | extern int nfs_write_inode(struct inode *,int); |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 607f6eb9cdb5..af4d0f1e402c 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | static void nfs_expire_automounts(struct work_struct *work); | 21 | static void nfs_expire_automounts(struct work_struct *work); |
22 | 22 | ||
23 | LIST_HEAD(nfs_automount_list); | 23 | static LIST_HEAD(nfs_automount_list); |
24 | static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts); | 24 | static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts); |
25 | int nfs_mountpoint_expiry_timeout = 500 * HZ; | 25 | int nfs_mountpoint_expiry_timeout = 500 * HZ; |
26 | 26 | ||
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 1f7ea675e0c5..28bab67d1519 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -267,7 +267,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
267 | int status; | 267 | int status; |
268 | 268 | ||
269 | if ((status = ntohl(*p++))) | 269 | if ((status = ntohl(*p++))) |
270 | return -nfs_stat_to_errno(status); | 270 | return nfs_stat_to_errno(status); |
271 | p = xdr_decode_fattr(p, res->fattr); | 271 | p = xdr_decode_fattr(p, res->fattr); |
272 | 272 | ||
273 | count = ntohl(*p++); | 273 | count = ntohl(*p++); |
@@ -428,11 +428,11 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
428 | size_t hdrlen; | 428 | size_t hdrlen; |
429 | unsigned int pglen, recvd; | 429 | unsigned int pglen, recvd; |
430 | u32 len; | 430 | u32 len; |
431 | int status, nr; | 431 | int status, nr = 0; |
432 | __be32 *end, *entry, *kaddr; | 432 | __be32 *end, *entry, *kaddr; |
433 | 433 | ||
434 | if ((status = ntohl(*p++))) | 434 | if ((status = ntohl(*p++))) |
435 | return -nfs_stat_to_errno(status); | 435 | return nfs_stat_to_errno(status); |
436 | 436 | ||
437 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; | 437 | hdrlen = (u8 *) p - (u8 *) iov->iov_base; |
438 | if (iov->iov_len < hdrlen) { | 438 | if (iov->iov_len < hdrlen) { |
@@ -452,7 +452,12 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
452 | kaddr = p = kmap_atomic(*page, KM_USER0); | 452 | kaddr = p = kmap_atomic(*page, KM_USER0); |
453 | end = (__be32 *)((char *)p + pglen); | 453 | end = (__be32 *)((char *)p + pglen); |
454 | entry = p; | 454 | entry = p; |
455 | for (nr = 0; *p++; nr++) { | 455 | |
456 | /* Make sure the packet actually has a value_follows and EOF entry */ | ||
457 | if ((entry + 1) > end) | ||
458 | goto short_pkt; | ||
459 | |||
460 | for (; *p++; nr++) { | ||
456 | if (p + 2 > end) | 461 | if (p + 2 > end) |
457 | goto short_pkt; | 462 | goto short_pkt; |
458 | p++; /* fileid */ | 463 | p++; /* fileid */ |
@@ -467,18 +472,32 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
467 | goto short_pkt; | 472 | goto short_pkt; |
468 | entry = p; | 473 | entry = p; |
469 | } | 474 | } |
470 | if (!nr && (entry[0] != 0 || entry[1] == 0)) | 475 | |
471 | goto short_pkt; | 476 | /* |
477 | * Apparently some server sends responses that are a valid size, but | ||
478 | * contain no entries, and have value_follows==0 and EOF==0. For | ||
479 | * those, just set the EOF marker. | ||
480 | */ | ||
481 | if (!nr && entry[1] == 0) { | ||
482 | dprintk("NFS: readdir reply truncated!\n"); | ||
483 | entry[1] = 1; | ||
484 | } | ||
472 | out: | 485 | out: |
473 | kunmap_atomic(kaddr, KM_USER0); | 486 | kunmap_atomic(kaddr, KM_USER0); |
474 | return nr; | 487 | return nr; |
475 | short_pkt: | 488 | short_pkt: |
489 | /* | ||
490 | * When we get a short packet there are 2 possibilities. We can | ||
491 | * return an error, or fix up the response to look like a valid | ||
492 | * response and return what we have so far. If there are no | ||
493 | * entries and the packet was short, then return -EIO. If there | ||
494 | * are valid entries in the response, return them and pretend that | ||
495 | * the call was successful, but incomplete. The caller can retry the | ||
496 | * readdir starting at the last cookie. | ||
497 | */ | ||
476 | entry[0] = entry[1] = 0; | 498 | entry[0] = entry[1] = 0; |
477 | /* truncate listing ? */ | 499 | if (!nr) |
478 | if (!nr) { | 500 | nr = -errno_NFSERR_IO; |
479 | dprintk("NFS: readdir reply truncated!\n"); | ||
480 | entry[1] = 1; | ||
481 | } | ||
482 | goto out; | 501 | goto out; |
483 | err_unmap: | 502 | err_unmap: |
484 | nr = -errno_NFSERR_IO; | 503 | nr = -errno_NFSERR_IO; |
@@ -518,7 +537,7 @@ nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
518 | int status; | 537 | int status; |
519 | 538 | ||
520 | if ((status = ntohl(*p++)) != 0) | 539 | if ((status = ntohl(*p++)) != 0) |
521 | status = -nfs_stat_to_errno(status); | 540 | status = nfs_stat_to_errno(status); |
522 | return status; | 541 | return status; |
523 | } | 542 | } |
524 | 543 | ||
@@ -532,7 +551,7 @@ nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
532 | int status; | 551 | int status; |
533 | 552 | ||
534 | if ((status = ntohl(*p++))) | 553 | if ((status = ntohl(*p++))) |
535 | return -nfs_stat_to_errno(status); | 554 | return nfs_stat_to_errno(status); |
536 | xdr_decode_fattr(p, fattr); | 555 | xdr_decode_fattr(p, fattr); |
537 | return 0; | 556 | return 0; |
538 | } | 557 | } |
@@ -547,7 +566,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res) | |||
547 | int status; | 566 | int status; |
548 | 567 | ||
549 | if ((status = ntohl(*p++))) | 568 | if ((status = ntohl(*p++))) |
550 | return -nfs_stat_to_errno(status); | 569 | return nfs_stat_to_errno(status); |
551 | p = xdr_decode_fhandle(p, res->fh); | 570 | p = xdr_decode_fhandle(p, res->fh); |
552 | xdr_decode_fattr(p, res->fattr); | 571 | xdr_decode_fattr(p, res->fattr); |
553 | return 0; | 572 | return 0; |
@@ -585,7 +604,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) | |||
585 | int status; | 604 | int status; |
586 | 605 | ||
587 | if ((status = ntohl(*p++))) | 606 | if ((status = ntohl(*p++))) |
588 | return -nfs_stat_to_errno(status); | 607 | return nfs_stat_to_errno(status); |
589 | /* Convert length of symlink */ | 608 | /* Convert length of symlink */ |
590 | len = ntohl(*p++); | 609 | len = ntohl(*p++); |
591 | if (len >= rcvbuf->page_len) { | 610 | if (len >= rcvbuf->page_len) { |
@@ -634,7 +653,7 @@ nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res) | |||
634 | int status; | 653 | int status; |
635 | 654 | ||
636 | if ((status = ntohl(*p++))) | 655 | if ((status = ntohl(*p++))) |
637 | return -nfs_stat_to_errno(status); | 656 | return nfs_stat_to_errno(status); |
638 | 657 | ||
639 | res->tsize = ntohl(*p++); | 658 | res->tsize = ntohl(*p++); |
640 | res->bsize = ntohl(*p++); | 659 | res->bsize = ntohl(*p++); |
@@ -653,39 +672,39 @@ static struct { | |||
653 | int errno; | 672 | int errno; |
654 | } nfs_errtbl[] = { | 673 | } nfs_errtbl[] = { |
655 | { NFS_OK, 0 }, | 674 | { NFS_OK, 0 }, |
656 | { NFSERR_PERM, EPERM }, | 675 | { NFSERR_PERM, -EPERM }, |
657 | { NFSERR_NOENT, ENOENT }, | 676 | { NFSERR_NOENT, -ENOENT }, |
658 | { NFSERR_IO, errno_NFSERR_IO }, | 677 | { NFSERR_IO, -errno_NFSERR_IO}, |
659 | { NFSERR_NXIO, ENXIO }, | 678 | { NFSERR_NXIO, -ENXIO }, |
660 | /* { NFSERR_EAGAIN, EAGAIN }, */ | 679 | /* { NFSERR_EAGAIN, -EAGAIN }, */ |
661 | { NFSERR_ACCES, EACCES }, | 680 | { NFSERR_ACCES, -EACCES }, |
662 | { NFSERR_EXIST, EEXIST }, | 681 | { NFSERR_EXIST, -EEXIST }, |
663 | { NFSERR_XDEV, EXDEV }, | 682 | { NFSERR_XDEV, -EXDEV }, |
664 | { NFSERR_NODEV, ENODEV }, | 683 | { NFSERR_NODEV, -ENODEV }, |
665 | { NFSERR_NOTDIR, ENOTDIR }, | 684 | { NFSERR_NOTDIR, -ENOTDIR }, |
666 | { NFSERR_ISDIR, EISDIR }, | 685 | { NFSERR_ISDIR, -EISDIR }, |
667 | { NFSERR_INVAL, EINVAL }, | 686 | { NFSERR_INVAL, -EINVAL }, |
668 | { NFSERR_FBIG, EFBIG }, | 687 | { NFSERR_FBIG, -EFBIG }, |
669 | { NFSERR_NOSPC, ENOSPC }, | 688 | { NFSERR_NOSPC, -ENOSPC }, |
670 | { NFSERR_ROFS, EROFS }, | 689 | { NFSERR_ROFS, -EROFS }, |
671 | { NFSERR_MLINK, EMLINK }, | 690 | { NFSERR_MLINK, -EMLINK }, |
672 | { NFSERR_NAMETOOLONG, ENAMETOOLONG }, | 691 | { NFSERR_NAMETOOLONG, -ENAMETOOLONG }, |
673 | { NFSERR_NOTEMPTY, ENOTEMPTY }, | 692 | { NFSERR_NOTEMPTY, -ENOTEMPTY }, |
674 | { NFSERR_DQUOT, EDQUOT }, | 693 | { NFSERR_DQUOT, -EDQUOT }, |
675 | { NFSERR_STALE, ESTALE }, | 694 | { NFSERR_STALE, -ESTALE }, |
676 | { NFSERR_REMOTE, EREMOTE }, | 695 | { NFSERR_REMOTE, -EREMOTE }, |
677 | #ifdef EWFLUSH | 696 | #ifdef EWFLUSH |
678 | { NFSERR_WFLUSH, EWFLUSH }, | 697 | { NFSERR_WFLUSH, -EWFLUSH }, |
679 | #endif | 698 | #endif |
680 | { NFSERR_BADHANDLE, EBADHANDLE }, | 699 | { NFSERR_BADHANDLE, -EBADHANDLE }, |
681 | { NFSERR_NOT_SYNC, ENOTSYNC }, | 700 | { NFSERR_NOT_SYNC, -ENOTSYNC }, |
682 | { NFSERR_BAD_COOKIE, EBADCOOKIE }, | 701 | { NFSERR_BAD_COOKIE, -EBADCOOKIE }, |
683 | { NFSERR_NOTSUPP, ENOTSUPP }, | 702 | { NFSERR_NOTSUPP, -ENOTSUPP }, |
684 | { NFSERR_TOOSMALL, ETOOSMALL }, | 703 | { NFSERR_TOOSMALL, -ETOOSMALL }, |
685 | { NFSERR_SERVERFAULT, ESERVERFAULT }, | 704 | { NFSERR_SERVERFAULT, -ESERVERFAULT }, |
686 | { NFSERR_BADTYPE, EBADTYPE }, | 705 | { NFSERR_BADTYPE, -EBADTYPE }, |
687 | { NFSERR_JUKEBOX, EJUKEBOX }, | 706 | { NFSERR_JUKEBOX, -EJUKEBOX }, |
688 | { -1, EIO } | 707 | { -1, -EIO } |
689 | }; | 708 | }; |
690 | 709 | ||
691 | /* | 710 | /* |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 3917e2fa4e40..11cdddec1432 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -508,14 +508,14 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
508 | struct page **page; | 508 | struct page **page; |
509 | size_t hdrlen; | 509 | size_t hdrlen; |
510 | u32 len, recvd, pglen; | 510 | u32 len, recvd, pglen; |
511 | int status, nr; | 511 | int status, nr = 0; |
512 | __be32 *entry, *end, *kaddr; | 512 | __be32 *entry, *end, *kaddr; |
513 | 513 | ||
514 | status = ntohl(*p++); | 514 | status = ntohl(*p++); |
515 | /* Decode post_op_attrs */ | 515 | /* Decode post_op_attrs */ |
516 | p = xdr_decode_post_op_attr(p, res->dir_attr); | 516 | p = xdr_decode_post_op_attr(p, res->dir_attr); |
517 | if (status) | 517 | if (status) |
518 | return -nfs_stat_to_errno(status); | 518 | return nfs_stat_to_errno(status); |
519 | /* Decode verifier cookie */ | 519 | /* Decode verifier cookie */ |
520 | if (res->verf) { | 520 | if (res->verf) { |
521 | res->verf[0] = *p++; | 521 | res->verf[0] = *p++; |
@@ -542,7 +542,12 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
542 | kaddr = p = kmap_atomic(*page, KM_USER0); | 542 | kaddr = p = kmap_atomic(*page, KM_USER0); |
543 | end = (__be32 *)((char *)p + pglen); | 543 | end = (__be32 *)((char *)p + pglen); |
544 | entry = p; | 544 | entry = p; |
545 | for (nr = 0; *p++; nr++) { | 545 | |
546 | /* Make sure the packet actually has a value_follows and EOF entry */ | ||
547 | if ((entry + 1) > end) | ||
548 | goto short_pkt; | ||
549 | |||
550 | for (; *p++; nr++) { | ||
546 | if (p + 3 > end) | 551 | if (p + 3 > end) |
547 | goto short_pkt; | 552 | goto short_pkt; |
548 | p += 2; /* inode # */ | 553 | p += 2; /* inode # */ |
@@ -581,18 +586,32 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res | |||
581 | goto short_pkt; | 586 | goto short_pkt; |
582 | entry = p; | 587 | entry = p; |
583 | } | 588 | } |
584 | if (!nr && (entry[0] != 0 || entry[1] == 0)) | 589 | |
585 | goto short_pkt; | 590 | /* |
591 | * Apparently some server sends responses that are a valid size, but | ||
592 | * contain no entries, and have value_follows==0 and EOF==0. For | ||
593 | * those, just set the EOF marker. | ||
594 | */ | ||
595 | if (!nr && entry[1] == 0) { | ||
596 | dprintk("NFS: readdir reply truncated!\n"); | ||
597 | entry[1] = 1; | ||
598 | } | ||
586 | out: | 599 | out: |
587 | kunmap_atomic(kaddr, KM_USER0); | 600 | kunmap_atomic(kaddr, KM_USER0); |
588 | return nr; | 601 | return nr; |
589 | short_pkt: | 602 | short_pkt: |
603 | /* | ||
604 | * When we get a short packet there are 2 possibilities. We can | ||
605 | * return an error, or fix up the response to look like a valid | ||
606 | * response and return what we have so far. If there are no | ||
607 | * entries and the packet was short, then return -EIO. If there | ||
608 | * are valid entries in the response, return them and pretend that | ||
609 | * the call was successful, but incomplete. The caller can retry the | ||
610 | * readdir starting at the last cookie. | ||
611 | */ | ||
590 | entry[0] = entry[1] = 0; | 612 | entry[0] = entry[1] = 0; |
591 | /* truncate listing ? */ | 613 | if (!nr) |
592 | if (!nr) { | 614 | nr = -errno_NFSERR_IO; |
593 | dprintk("NFS: readdir reply truncated!\n"); | ||
594 | entry[1] = 1; | ||
595 | } | ||
596 | goto out; | 615 | goto out; |
597 | err_unmap: | 616 | err_unmap: |
598 | nr = -errno_NFSERR_IO; | 617 | nr = -errno_NFSERR_IO; |
@@ -732,7 +751,7 @@ nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
732 | int status; | 751 | int status; |
733 | 752 | ||
734 | if ((status = ntohl(*p++))) | 753 | if ((status = ntohl(*p++))) |
735 | return -nfs_stat_to_errno(status); | 754 | return nfs_stat_to_errno(status); |
736 | xdr_decode_fattr(p, fattr); | 755 | xdr_decode_fattr(p, fattr); |
737 | return 0; | 756 | return 0; |
738 | } | 757 | } |
@@ -747,7 +766,7 @@ nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
747 | int status; | 766 | int status; |
748 | 767 | ||
749 | if ((status = ntohl(*p++))) | 768 | if ((status = ntohl(*p++))) |
750 | status = -nfs_stat_to_errno(status); | 769 | status = nfs_stat_to_errno(status); |
751 | xdr_decode_wcc_data(p, fattr); | 770 | xdr_decode_wcc_data(p, fattr); |
752 | return status; | 771 | return status; |
753 | } | 772 | } |
@@ -767,7 +786,7 @@ nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res) | |||
767 | int status; | 786 | int status; |
768 | 787 | ||
769 | if ((status = ntohl(*p++))) { | 788 | if ((status = ntohl(*p++))) { |
770 | status = -nfs_stat_to_errno(status); | 789 | status = nfs_stat_to_errno(status); |
771 | } else { | 790 | } else { |
772 | if (!(p = xdr_decode_fhandle(p, res->fh))) | 791 | if (!(p = xdr_decode_fhandle(p, res->fh))) |
773 | return -errno_NFSERR_IO; | 792 | return -errno_NFSERR_IO; |
@@ -787,7 +806,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res) | |||
787 | 806 | ||
788 | p = xdr_decode_post_op_attr(p, res->fattr); | 807 | p = xdr_decode_post_op_attr(p, res->fattr); |
789 | if (status) | 808 | if (status) |
790 | return -nfs_stat_to_errno(status); | 809 | return nfs_stat_to_errno(status); |
791 | res->access = ntohl(*p++); | 810 | res->access = ntohl(*p++); |
792 | return 0; | 811 | return 0; |
793 | } | 812 | } |
@@ -824,7 +843,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
824 | p = xdr_decode_post_op_attr(p, fattr); | 843 | p = xdr_decode_post_op_attr(p, fattr); |
825 | 844 | ||
826 | if (status != 0) | 845 | if (status != 0) |
827 | return -nfs_stat_to_errno(status); | 846 | return nfs_stat_to_errno(status); |
828 | 847 | ||
829 | /* Convert length of symlink */ | 848 | /* Convert length of symlink */ |
830 | len = ntohl(*p++); | 849 | len = ntohl(*p++); |
@@ -872,7 +891,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) | |||
872 | p = xdr_decode_post_op_attr(p, res->fattr); | 891 | p = xdr_decode_post_op_attr(p, res->fattr); |
873 | 892 | ||
874 | if (status != 0) | 893 | if (status != 0) |
875 | return -nfs_stat_to_errno(status); | 894 | return nfs_stat_to_errno(status); |
876 | 895 | ||
877 | /* Decode reply count and EOF flag. NFSv3 is somewhat redundant | 896 | /* Decode reply count and EOF flag. NFSv3 is somewhat redundant |
878 | * in that it puts the count both in the res struct and in the | 897 | * in that it puts the count both in the res struct and in the |
@@ -922,7 +941,7 @@ nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) | |||
922 | p = xdr_decode_wcc_data(p, res->fattr); | 941 | p = xdr_decode_wcc_data(p, res->fattr); |
923 | 942 | ||
924 | if (status != 0) | 943 | if (status != 0) |
925 | return -nfs_stat_to_errno(status); | 944 | return nfs_stat_to_errno(status); |
926 | 945 | ||
927 | res->count = ntohl(*p++); | 946 | res->count = ntohl(*p++); |
928 | res->verf->committed = (enum nfs3_stable_how)ntohl(*p++); | 947 | res->verf->committed = (enum nfs3_stable_how)ntohl(*p++); |
@@ -953,7 +972,7 @@ nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res) | |||
953 | res->fattr->valid = 0; | 972 | res->fattr->valid = 0; |
954 | } | 973 | } |
955 | } else { | 974 | } else { |
956 | status = -nfs_stat_to_errno(status); | 975 | status = nfs_stat_to_errno(status); |
957 | } | 976 | } |
958 | p = xdr_decode_wcc_data(p, res->dir_attr); | 977 | p = xdr_decode_wcc_data(p, res->dir_attr); |
959 | return status; | 978 | return status; |
@@ -968,7 +987,7 @@ nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res) | |||
968 | int status; | 987 | int status; |
969 | 988 | ||
970 | if ((status = ntohl(*p++)) != 0) | 989 | if ((status = ntohl(*p++)) != 0) |
971 | status = -nfs_stat_to_errno(status); | 990 | status = nfs_stat_to_errno(status); |
972 | p = xdr_decode_wcc_data(p, res->fromattr); | 991 | p = xdr_decode_wcc_data(p, res->fromattr); |
973 | p = xdr_decode_wcc_data(p, res->toattr); | 992 | p = xdr_decode_wcc_data(p, res->toattr); |
974 | return status; | 993 | return status; |
@@ -983,7 +1002,7 @@ nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res) | |||
983 | int status; | 1002 | int status; |
984 | 1003 | ||
985 | if ((status = ntohl(*p++)) != 0) | 1004 | if ((status = ntohl(*p++)) != 0) |
986 | status = -nfs_stat_to_errno(status); | 1005 | status = nfs_stat_to_errno(status); |
987 | p = xdr_decode_post_op_attr(p, res->fattr); | 1006 | p = xdr_decode_post_op_attr(p, res->fattr); |
988 | p = xdr_decode_wcc_data(p, res->dir_attr); | 1007 | p = xdr_decode_wcc_data(p, res->dir_attr); |
989 | return status; | 1008 | return status; |
@@ -1001,7 +1020,7 @@ nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res) | |||
1001 | 1020 | ||
1002 | p = xdr_decode_post_op_attr(p, res->fattr); | 1021 | p = xdr_decode_post_op_attr(p, res->fattr); |
1003 | if (status != 0) | 1022 | if (status != 0) |
1004 | return -nfs_stat_to_errno(status); | 1023 | return nfs_stat_to_errno(status); |
1005 | 1024 | ||
1006 | p = xdr_decode_hyper(p, &res->tbytes); | 1025 | p = xdr_decode_hyper(p, &res->tbytes); |
1007 | p = xdr_decode_hyper(p, &res->fbytes); | 1026 | p = xdr_decode_hyper(p, &res->fbytes); |
@@ -1026,7 +1045,7 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res) | |||
1026 | 1045 | ||
1027 | p = xdr_decode_post_op_attr(p, res->fattr); | 1046 | p = xdr_decode_post_op_attr(p, res->fattr); |
1028 | if (status != 0) | 1047 | if (status != 0) |
1029 | return -nfs_stat_to_errno(status); | 1048 | return nfs_stat_to_errno(status); |
1030 | 1049 | ||
1031 | res->rtmax = ntohl(*p++); | 1050 | res->rtmax = ntohl(*p++); |
1032 | res->rtpref = ntohl(*p++); | 1051 | res->rtpref = ntohl(*p++); |
@@ -1054,7 +1073,7 @@ nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res) | |||
1054 | 1073 | ||
1055 | p = xdr_decode_post_op_attr(p, res->fattr); | 1074 | p = xdr_decode_post_op_attr(p, res->fattr); |
1056 | if (status != 0) | 1075 | if (status != 0) |
1057 | return -nfs_stat_to_errno(status); | 1076 | return nfs_stat_to_errno(status); |
1058 | res->max_link = ntohl(*p++); | 1077 | res->max_link = ntohl(*p++); |
1059 | res->max_namelen = ntohl(*p++); | 1078 | res->max_namelen = ntohl(*p++); |
1060 | 1079 | ||
@@ -1073,7 +1092,7 @@ nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res) | |||
1073 | status = ntohl(*p++); | 1092 | status = ntohl(*p++); |
1074 | p = xdr_decode_wcc_data(p, res->fattr); | 1093 | p = xdr_decode_wcc_data(p, res->fattr); |
1075 | if (status != 0) | 1094 | if (status != 0) |
1076 | return -nfs_stat_to_errno(status); | 1095 | return nfs_stat_to_errno(status); |
1077 | 1096 | ||
1078 | res->verf->verifier[0] = *p++; | 1097 | res->verf->verifier[0] = *p++; |
1079 | res->verf->verifier[1] = *p++; | 1098 | res->verf->verifier[1] = *p++; |
@@ -1095,7 +1114,7 @@ nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p, | |||
1095 | int err, base; | 1114 | int err, base; |
1096 | 1115 | ||
1097 | if (status != 0) | 1116 | if (status != 0) |
1098 | return -nfs_stat_to_errno(status); | 1117 | return nfs_stat_to_errno(status); |
1099 | p = xdr_decode_post_op_attr(p, res->fattr); | 1118 | p = xdr_decode_post_op_attr(p, res->fattr); |
1100 | res->mask = ntohl(*p++); | 1119 | res->mask = ntohl(*p++); |
1101 | if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) | 1120 | if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) |
@@ -1122,7 +1141,7 @@ nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
1122 | int status = ntohl(*p++); | 1141 | int status = ntohl(*p++); |
1123 | 1142 | ||
1124 | if (status) | 1143 | if (status) |
1125 | return -nfs_stat_to_errno(status); | 1144 | return nfs_stat_to_errno(status); |
1126 | xdr_decode_post_op_attr(p, fattr); | 1145 | xdr_decode_post_op_attr(p, fattr); |
1127 | return 0; | 1146 | return 0; |
1128 | } | 1147 | } |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7ce07862c2fb..dbc09271af02 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -51,6 +51,7 @@ | |||
51 | 51 | ||
52 | #include "nfs4_fs.h" | 52 | #include "nfs4_fs.h" |
53 | #include "delegation.h" | 53 | #include "delegation.h" |
54 | #include "internal.h" | ||
54 | #include "iostat.h" | 55 | #include "iostat.h" |
55 | 56 | ||
56 | #define NFSDBG_FACILITY NFSDBG_PROC | 57 | #define NFSDBG_FACILITY NFSDBG_PROC |
@@ -239,6 +240,8 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
239 | { | 240 | { |
240 | p->o_res.f_attr = &p->f_attr; | 241 | p->o_res.f_attr = &p->f_attr; |
241 | p->o_res.dir_attr = &p->dir_attr; | 242 | p->o_res.dir_attr = &p->dir_attr; |
243 | p->o_res.seqid = p->o_arg.seqid; | ||
244 | p->c_res.seqid = p->c_arg.seqid; | ||
242 | p->o_res.server = p->o_arg.server; | 245 | p->o_res.server = p->o_arg.server; |
243 | nfs_fattr_init(&p->f_attr); | 246 | nfs_fattr_init(&p->f_attr); |
244 | nfs_fattr_init(&p->dir_attr); | 247 | nfs_fattr_init(&p->dir_attr); |
@@ -729,7 +732,6 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | |||
729 | renew_lease(data->o_res.server, data->timestamp); | 732 | renew_lease(data->o_res.server, data->timestamp); |
730 | data->rpc_done = 1; | 733 | data->rpc_done = 1; |
731 | } | 734 | } |
732 | nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); | ||
733 | } | 735 | } |
734 | 736 | ||
735 | static void nfs4_open_confirm_release(void *calldata) | 737 | static void nfs4_open_confirm_release(void *calldata) |
@@ -773,6 +775,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) | |||
773 | .rpc_message = &msg, | 775 | .rpc_message = &msg, |
774 | .callback_ops = &nfs4_open_confirm_ops, | 776 | .callback_ops = &nfs4_open_confirm_ops, |
775 | .callback_data = data, | 777 | .callback_data = data, |
778 | .workqueue = nfsiod_workqueue, | ||
776 | .flags = RPC_TASK_ASYNC, | 779 | .flags = RPC_TASK_ASYNC, |
777 | }; | 780 | }; |
778 | int status; | 781 | int status; |
@@ -858,7 +861,6 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
858 | if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)) | 861 | if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)) |
859 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | 862 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
860 | } | 863 | } |
861 | nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid); | ||
862 | data->rpc_done = 1; | 864 | data->rpc_done = 1; |
863 | } | 865 | } |
864 | 866 | ||
@@ -910,6 +912,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
910 | .rpc_message = &msg, | 912 | .rpc_message = &msg, |
911 | .callback_ops = &nfs4_open_ops, | 913 | .callback_ops = &nfs4_open_ops, |
912 | .callback_data = data, | 914 | .callback_data = data, |
915 | .workqueue = nfsiod_workqueue, | ||
913 | .flags = RPC_TASK_ASYNC, | 916 | .flags = RPC_TASK_ASYNC, |
914 | }; | 917 | }; |
915 | int status; | 918 | int status; |
@@ -979,11 +982,8 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s | |||
979 | if (IS_ERR(opendata)) | 982 | if (IS_ERR(opendata)) |
980 | return PTR_ERR(opendata); | 983 | return PTR_ERR(opendata); |
981 | ret = nfs4_open_recover(opendata, state); | 984 | ret = nfs4_open_recover(opendata, state); |
982 | if (ret == -ESTALE) { | 985 | if (ret == -ESTALE) |
983 | /* Invalidate the state owner so we don't ever use it again */ | ||
984 | nfs4_drop_state_owner(state->owner); | ||
985 | d_drop(ctx->path.dentry); | 986 | d_drop(ctx->path.dentry); |
986 | } | ||
987 | nfs4_opendata_put(opendata); | 987 | nfs4_opendata_put(opendata); |
988 | return ret; | 988 | return ret; |
989 | } | 989 | } |
@@ -1226,7 +1226,6 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1226 | /* hmm. we are done with the inode, and in the process of freeing | 1226 | /* hmm. we are done with the inode, and in the process of freeing |
1227 | * the state_owner. we keep this around to process errors | 1227 | * the state_owner. we keep this around to process errors |
1228 | */ | 1228 | */ |
1229 | nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); | ||
1230 | switch (task->tk_status) { | 1229 | switch (task->tk_status) { |
1231 | case 0: | 1230 | case 0: |
1232 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); | 1231 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); |
@@ -1315,6 +1314,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1315 | .rpc_client = server->client, | 1314 | .rpc_client = server->client, |
1316 | .rpc_message = &msg, | 1315 | .rpc_message = &msg, |
1317 | .callback_ops = &nfs4_close_ops, | 1316 | .callback_ops = &nfs4_close_ops, |
1317 | .workqueue = nfsiod_workqueue, | ||
1318 | .flags = RPC_TASK_ASYNC, | 1318 | .flags = RPC_TASK_ASYNC, |
1319 | }; | 1319 | }; |
1320 | int status = -ENOMEM; | 1320 | int status = -ENOMEM; |
@@ -1332,6 +1332,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1332 | goto out_free_calldata; | 1332 | goto out_free_calldata; |
1333 | calldata->arg.bitmask = server->attr_bitmask; | 1333 | calldata->arg.bitmask = server->attr_bitmask; |
1334 | calldata->res.fattr = &calldata->fattr; | 1334 | calldata->res.fattr = &calldata->fattr; |
1335 | calldata->res.seqid = calldata->arg.seqid; | ||
1335 | calldata->res.server = server; | 1336 | calldata->res.server = server; |
1336 | calldata->path.mnt = mntget(path->mnt); | 1337 | calldata->path.mnt = mntget(path->mnt); |
1337 | calldata->path.dentry = dget(path->dentry); | 1338 | calldata->path.dentry = dget(path->dentry); |
@@ -1404,7 +1405,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
1404 | BUG_ON(nd->intent.open.flags & O_CREAT); | 1405 | BUG_ON(nd->intent.open.flags & O_CREAT); |
1405 | } | 1406 | } |
1406 | 1407 | ||
1407 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 1408 | cred = rpc_lookup_cred(); |
1408 | if (IS_ERR(cred)) | 1409 | if (IS_ERR(cred)) |
1409 | return (struct dentry *)cred; | 1410 | return (struct dentry *)cred; |
1410 | parent = dentry->d_parent; | 1411 | parent = dentry->d_parent; |
@@ -1439,7 +1440,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1439 | struct rpc_cred *cred; | 1440 | struct rpc_cred *cred; |
1440 | struct nfs4_state *state; | 1441 | struct nfs4_state *state; |
1441 | 1442 | ||
1442 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 1443 | cred = rpc_lookup_cred(); |
1443 | if (IS_ERR(cred)) | 1444 | if (IS_ERR(cred)) |
1444 | return PTR_ERR(cred); | 1445 | return PTR_ERR(cred); |
1445 | state = nfs4_do_open(dir, &path, openflags, NULL, cred); | 1446 | state = nfs4_do_open(dir, &path, openflags, NULL, cred); |
@@ -1656,7 +1657,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, | |||
1656 | 1657 | ||
1657 | nfs_fattr_init(fattr); | 1658 | nfs_fattr_init(fattr); |
1658 | 1659 | ||
1659 | cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); | 1660 | cred = rpc_lookup_cred(); |
1660 | if (IS_ERR(cred)) | 1661 | if (IS_ERR(cred)) |
1661 | return PTR_ERR(cred); | 1662 | return PTR_ERR(cred); |
1662 | 1663 | ||
@@ -1892,7 +1893,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
1892 | struct rpc_cred *cred; | 1893 | struct rpc_cred *cred; |
1893 | int status = 0; | 1894 | int status = 0; |
1894 | 1895 | ||
1895 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 1896 | cred = rpc_lookup_cred(); |
1896 | if (IS_ERR(cred)) { | 1897 | if (IS_ERR(cred)) { |
1897 | status = PTR_ERR(cred); | 1898 | status = PTR_ERR(cred); |
1898 | goto out; | 1899 | goto out; |
@@ -2761,10 +2762,10 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server) | |||
2761 | case -NFS4ERR_STALE_CLIENTID: | 2762 | case -NFS4ERR_STALE_CLIENTID: |
2762 | case -NFS4ERR_STALE_STATEID: | 2763 | case -NFS4ERR_STALE_STATEID: |
2763 | case -NFS4ERR_EXPIRED: | 2764 | case -NFS4ERR_EXPIRED: |
2764 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL, NULL); | 2765 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); |
2765 | nfs4_schedule_state_recovery(clp); | 2766 | nfs4_schedule_state_recovery(clp); |
2766 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0) | 2767 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) == 0) |
2767 | rpc_wake_up_task(task); | 2768 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); |
2768 | task->tk_status = 0; | 2769 | task->tk_status = 0; |
2769 | return -EAGAIN; | 2770 | return -EAGAIN; |
2770 | case -NFS4ERR_DELAY: | 2771 | case -NFS4ERR_DELAY: |
@@ -2884,7 +2885,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po | |||
2884 | RPC_DISPLAY_ADDR), | 2885 | RPC_DISPLAY_ADDR), |
2885 | rpc_peeraddr2str(clp->cl_rpcclient, | 2886 | rpc_peeraddr2str(clp->cl_rpcclient, |
2886 | RPC_DISPLAY_PROTO), | 2887 | RPC_DISPLAY_PROTO), |
2887 | cred->cr_ops->cr_name, | 2888 | clp->cl_rpcclient->cl_auth->au_ops->au_name, |
2888 | clp->cl_id_uniquifier); | 2889 | clp->cl_id_uniquifier); |
2889 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, | 2890 | setclientid.sc_netid_len = scnprintf(setclientid.sc_netid, |
2890 | sizeof(setclientid.sc_netid), | 2891 | sizeof(setclientid.sc_netid), |
@@ -3158,6 +3159,7 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | |||
3158 | p->arg.fh = NFS_FH(inode); | 3159 | p->arg.fh = NFS_FH(inode); |
3159 | p->arg.fl = &p->fl; | 3160 | p->arg.fl = &p->fl; |
3160 | p->arg.seqid = seqid; | 3161 | p->arg.seqid = seqid; |
3162 | p->res.seqid = seqid; | ||
3161 | p->arg.stateid = &lsp->ls_stateid; | 3163 | p->arg.stateid = &lsp->ls_stateid; |
3162 | p->lsp = lsp; | 3164 | p->lsp = lsp; |
3163 | atomic_inc(&lsp->ls_count); | 3165 | atomic_inc(&lsp->ls_count); |
@@ -3183,7 +3185,6 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3183 | 3185 | ||
3184 | if (RPC_ASSASSINATED(task)) | 3186 | if (RPC_ASSASSINATED(task)) |
3185 | return; | 3187 | return; |
3186 | nfs_increment_lock_seqid(task->tk_status, calldata->arg.seqid); | ||
3187 | switch (task->tk_status) { | 3188 | switch (task->tk_status) { |
3188 | case 0: | 3189 | case 0: |
3189 | memcpy(calldata->lsp->ls_stateid.data, | 3190 | memcpy(calldata->lsp->ls_stateid.data, |
@@ -3235,6 +3236,7 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |||
3235 | .rpc_client = NFS_CLIENT(lsp->ls_state->inode), | 3236 | .rpc_client = NFS_CLIENT(lsp->ls_state->inode), |
3236 | .rpc_message = &msg, | 3237 | .rpc_message = &msg, |
3237 | .callback_ops = &nfs4_locku_ops, | 3238 | .callback_ops = &nfs4_locku_ops, |
3239 | .workqueue = nfsiod_workqueue, | ||
3238 | .flags = RPC_TASK_ASYNC, | 3240 | .flags = RPC_TASK_ASYNC, |
3239 | }; | 3241 | }; |
3240 | 3242 | ||
@@ -3261,6 +3263,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
3261 | struct nfs4_lock_state *lsp; | 3263 | struct nfs4_lock_state *lsp; |
3262 | struct rpc_task *task; | 3264 | struct rpc_task *task; |
3263 | int status = 0; | 3265 | int status = 0; |
3266 | unsigned char fl_flags = request->fl_flags; | ||
3264 | 3267 | ||
3265 | status = nfs4_set_lock_state(state, request); | 3268 | status = nfs4_set_lock_state(state, request); |
3266 | /* Unlock _before_ we do the RPC call */ | 3269 | /* Unlock _before_ we do the RPC call */ |
@@ -3284,6 +3287,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
3284 | status = nfs4_wait_for_completion_rpc_task(task); | 3287 | status = nfs4_wait_for_completion_rpc_task(task); |
3285 | rpc_put_task(task); | 3288 | rpc_put_task(task); |
3286 | out: | 3289 | out: |
3290 | request->fl_flags = fl_flags; | ||
3287 | return status; | 3291 | return status; |
3288 | } | 3292 | } |
3289 | 3293 | ||
@@ -3320,6 +3324,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
3320 | p->arg.lock_stateid = &lsp->ls_stateid; | 3324 | p->arg.lock_stateid = &lsp->ls_stateid; |
3321 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 3325 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
3322 | p->arg.lock_owner.id = lsp->ls_id.id; | 3326 | p->arg.lock_owner.id = lsp->ls_id.id; |
3327 | p->res.lock_seqid = p->arg.lock_seqid; | ||
3323 | p->lsp = lsp; | 3328 | p->lsp = lsp; |
3324 | atomic_inc(&lsp->ls_count); | 3329 | atomic_inc(&lsp->ls_count); |
3325 | p->ctx = get_nfs_open_context(ctx); | 3330 | p->ctx = get_nfs_open_context(ctx); |
@@ -3346,6 +3351,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
3346 | return; | 3351 | return; |
3347 | data->arg.open_stateid = &state->stateid; | 3352 | data->arg.open_stateid = &state->stateid; |
3348 | data->arg.new_lock_owner = 1; | 3353 | data->arg.new_lock_owner = 1; |
3354 | data->res.open_seqid = data->arg.open_seqid; | ||
3349 | } else | 3355 | } else |
3350 | data->arg.new_lock_owner = 0; | 3356 | data->arg.new_lock_owner = 0; |
3351 | data->timestamp = jiffies; | 3357 | data->timestamp = jiffies; |
@@ -3363,7 +3369,6 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
3363 | if (RPC_ASSASSINATED(task)) | 3369 | if (RPC_ASSASSINATED(task)) |
3364 | goto out; | 3370 | goto out; |
3365 | if (data->arg.new_lock_owner != 0) { | 3371 | if (data->arg.new_lock_owner != 0) { |
3366 | nfs_increment_open_seqid(data->rpc_status, data->arg.open_seqid); | ||
3367 | if (data->rpc_status == 0) | 3372 | if (data->rpc_status == 0) |
3368 | nfs_confirm_seqid(&data->lsp->ls_seqid, 0); | 3373 | nfs_confirm_seqid(&data->lsp->ls_seqid, 0); |
3369 | else | 3374 | else |
@@ -3375,7 +3380,6 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
3375 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; | 3380 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; |
3376 | renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp); | 3381 | renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp); |
3377 | } | 3382 | } |
3378 | nfs_increment_lock_seqid(data->rpc_status, data->arg.lock_seqid); | ||
3379 | out: | 3383 | out: |
3380 | dprintk("%s: done, ret = %d!\n", __FUNCTION__, data->rpc_status); | 3384 | dprintk("%s: done, ret = %d!\n", __FUNCTION__, data->rpc_status); |
3381 | } | 3385 | } |
@@ -3419,6 +3423,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
3419 | .rpc_client = NFS_CLIENT(state->inode), | 3423 | .rpc_client = NFS_CLIENT(state->inode), |
3420 | .rpc_message = &msg, | 3424 | .rpc_message = &msg, |
3421 | .callback_ops = &nfs4_lock_ops, | 3425 | .callback_ops = &nfs4_lock_ops, |
3426 | .workqueue = nfsiod_workqueue, | ||
3422 | .flags = RPC_TASK_ASYNC, | 3427 | .flags = RPC_TASK_ASYNC, |
3423 | }; | 3428 | }; |
3424 | int ret; | 3429 | int ret; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index b962397004c1..46eb624e4f16 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -71,6 +71,29 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | |||
71 | return status; | 71 | return status; |
72 | } | 72 | } |
73 | 73 | ||
74 | static struct rpc_cred *nfs4_get_machine_cred(struct nfs_client *clp) | ||
75 | { | ||
76 | struct rpc_cred *cred = NULL; | ||
77 | |||
78 | spin_lock(&clp->cl_lock); | ||
79 | if (clp->cl_machine_cred != NULL) | ||
80 | cred = get_rpccred(clp->cl_machine_cred); | ||
81 | spin_unlock(&clp->cl_lock); | ||
82 | return cred; | ||
83 | } | ||
84 | |||
85 | static void nfs4_clear_machine_cred(struct nfs_client *clp) | ||
86 | { | ||
87 | struct rpc_cred *cred; | ||
88 | |||
89 | spin_lock(&clp->cl_lock); | ||
90 | cred = clp->cl_machine_cred; | ||
91 | clp->cl_machine_cred = NULL; | ||
92 | spin_unlock(&clp->cl_lock); | ||
93 | if (cred != NULL) | ||
94 | put_rpccred(cred); | ||
95 | } | ||
96 | |||
74 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) | 97 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) |
75 | { | 98 | { |
76 | struct nfs4_state_owner *sp; | 99 | struct nfs4_state_owner *sp; |
@@ -91,13 +114,18 @@ static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | |||
91 | { | 114 | { |
92 | struct nfs4_state_owner *sp; | 115 | struct nfs4_state_owner *sp; |
93 | struct rb_node *pos; | 116 | struct rb_node *pos; |
117 | struct rpc_cred *cred; | ||
94 | 118 | ||
119 | cred = nfs4_get_machine_cred(clp); | ||
120 | if (cred != NULL) | ||
121 | goto out; | ||
95 | pos = rb_first(&clp->cl_state_owners); | 122 | pos = rb_first(&clp->cl_state_owners); |
96 | if (pos != NULL) { | 123 | if (pos != NULL) { |
97 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | 124 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); |
98 | return get_rpccred(sp->so_cred); | 125 | cred = get_rpccred(sp->so_cred); |
99 | } | 126 | } |
100 | return NULL; | 127 | out: |
128 | return cred; | ||
101 | } | 129 | } |
102 | 130 | ||
103 | static void nfs_alloc_unique_id(struct rb_root *root, struct nfs_unique_id *new, | 131 | static void nfs_alloc_unique_id(struct rb_root *root, struct nfs_unique_id *new, |
@@ -292,8 +320,10 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
292 | spin_unlock(&clp->cl_lock); | 320 | spin_unlock(&clp->cl_lock); |
293 | if (sp == new) | 321 | if (sp == new) |
294 | get_rpccred(cred); | 322 | get_rpccred(cred); |
295 | else | 323 | else { |
324 | rpc_destroy_wait_queue(&new->so_sequence.wait); | ||
296 | kfree(new); | 325 | kfree(new); |
326 | } | ||
297 | return sp; | 327 | return sp; |
298 | } | 328 | } |
299 | 329 | ||
@@ -310,6 +340,7 @@ void nfs4_put_state_owner(struct nfs4_state_owner *sp) | |||
310 | return; | 340 | return; |
311 | nfs4_remove_state_owner(clp, sp); | 341 | nfs4_remove_state_owner(clp, sp); |
312 | spin_unlock(&clp->cl_lock); | 342 | spin_unlock(&clp->cl_lock); |
343 | rpc_destroy_wait_queue(&sp->so_sequence.wait); | ||
313 | put_rpccred(cred); | 344 | put_rpccred(cred); |
314 | kfree(sp); | 345 | kfree(sp); |
315 | } | 346 | } |
@@ -529,6 +560,7 @@ static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) | |||
529 | spin_lock(&clp->cl_lock); | 560 | spin_lock(&clp->cl_lock); |
530 | nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id); | 561 | nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id); |
531 | spin_unlock(&clp->cl_lock); | 562 | spin_unlock(&clp->cl_lock); |
563 | rpc_destroy_wait_queue(&lsp->ls_sequence.wait); | ||
532 | kfree(lsp); | 564 | kfree(lsp); |
533 | } | 565 | } |
534 | 566 | ||
@@ -731,7 +763,7 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) | |||
731 | list_add_tail(&seqid->list, &sequence->list); | 763 | list_add_tail(&seqid->list, &sequence->list); |
732 | if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid) | 764 | if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid) |
733 | goto unlock; | 765 | goto unlock; |
734 | rpc_sleep_on(&sequence->wait, task, NULL, NULL); | 766 | rpc_sleep_on(&sequence->wait, task, NULL); |
735 | status = -EAGAIN; | 767 | status = -EAGAIN; |
736 | unlock: | 768 | unlock: |
737 | spin_unlock(&sequence->lock); | 769 | spin_unlock(&sequence->lock); |
@@ -920,10 +952,10 @@ restart_loop: | |||
920 | if (cred != NULL) { | 952 | if (cred != NULL) { |
921 | /* Yes there are: try to renew the old lease */ | 953 | /* Yes there are: try to renew the old lease */ |
922 | status = nfs4_proc_renew(clp, cred); | 954 | status = nfs4_proc_renew(clp, cred); |
955 | put_rpccred(cred); | ||
923 | switch (status) { | 956 | switch (status) { |
924 | case 0: | 957 | case 0: |
925 | case -NFS4ERR_CB_PATH_DOWN: | 958 | case -NFS4ERR_CB_PATH_DOWN: |
926 | put_rpccred(cred); | ||
927 | goto out; | 959 | goto out; |
928 | case -NFS4ERR_STALE_CLIENTID: | 960 | case -NFS4ERR_STALE_CLIENTID: |
929 | case -NFS4ERR_LEASE_MOVED: | 961 | case -NFS4ERR_LEASE_MOVED: |
@@ -932,14 +964,19 @@ restart_loop: | |||
932 | } else { | 964 | } else { |
933 | /* "reboot" to ensure we clear all state on the server */ | 965 | /* "reboot" to ensure we clear all state on the server */ |
934 | clp->cl_boot_time = CURRENT_TIME; | 966 | clp->cl_boot_time = CURRENT_TIME; |
935 | cred = nfs4_get_setclientid_cred(clp); | ||
936 | } | 967 | } |
937 | /* We're going to have to re-establish a clientid */ | 968 | /* We're going to have to re-establish a clientid */ |
938 | nfs4_state_mark_reclaim(clp); | 969 | nfs4_state_mark_reclaim(clp); |
939 | status = -ENOENT; | 970 | status = -ENOENT; |
971 | cred = nfs4_get_setclientid_cred(clp); | ||
940 | if (cred != NULL) { | 972 | if (cred != NULL) { |
941 | status = nfs4_init_client(clp, cred); | 973 | status = nfs4_init_client(clp, cred); |
942 | put_rpccred(cred); | 974 | put_rpccred(cred); |
975 | /* Handle case where the user hasn't set up machine creds */ | ||
976 | if (status == -EACCES && cred == clp->cl_machine_cred) { | ||
977 | nfs4_clear_machine_cred(clp); | ||
978 | goto restart_loop; | ||
979 | } | ||
943 | } | 980 | } |
944 | if (status) | 981 | if (status) |
945 | goto out_error; | 982 | goto out_error; |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index db1ed9c46ede..5a2d64927b35 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -110,7 +110,7 @@ static int nfs4_stat_to_errno(int); | |||
110 | #define decode_savefh_maxsz (op_decode_hdr_maxsz) | 110 | #define decode_savefh_maxsz (op_decode_hdr_maxsz) |
111 | #define encode_restorefh_maxsz (op_encode_hdr_maxsz) | 111 | #define encode_restorefh_maxsz (op_encode_hdr_maxsz) |
112 | #define decode_restorefh_maxsz (op_decode_hdr_maxsz) | 112 | #define decode_restorefh_maxsz (op_decode_hdr_maxsz) |
113 | #define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2) | 113 | #define encode_fsinfo_maxsz (encode_getattr_maxsz) |
114 | #define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 11) | 114 | #define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 11) |
115 | #define encode_renew_maxsz (op_encode_hdr_maxsz + 3) | 115 | #define encode_renew_maxsz (op_encode_hdr_maxsz + 3) |
116 | #define decode_renew_maxsz (op_decode_hdr_maxsz) | 116 | #define decode_renew_maxsz (op_decode_hdr_maxsz) |
@@ -1191,8 +1191,8 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1191 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; | 1191 | attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; |
1192 | WRITE32(attrs[0] & readdir->bitmask[0]); | 1192 | WRITE32(attrs[0] & readdir->bitmask[0]); |
1193 | WRITE32(attrs[1] & readdir->bitmask[1]); | 1193 | WRITE32(attrs[1] & readdir->bitmask[1]); |
1194 | dprintk("%s: cookie = %Lu, verifier = 0x%x%x, bitmap = 0x%x%x\n", | 1194 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", |
1195 | __FUNCTION__, | 1195 | __func__, |
1196 | (unsigned long long)readdir->cookie, | 1196 | (unsigned long long)readdir->cookie, |
1197 | ((u32 *)readdir->verifier.data)[0], | 1197 | ((u32 *)readdir->verifier.data)[0], |
1198 | ((u32 *)readdir->verifier.data)[1], | 1198 | ((u32 *)readdir->verifier.data)[1], |
@@ -2241,7 +2241,7 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) | |||
2241 | } | 2241 | } |
2242 | READ32(nfserr); | 2242 | READ32(nfserr); |
2243 | if (nfserr != NFS_OK) | 2243 | if (nfserr != NFS_OK) |
2244 | return -nfs4_stat_to_errno(nfserr); | 2244 | return nfs4_stat_to_errno(nfserr); |
2245 | return 0; | 2245 | return 0; |
2246 | } | 2246 | } |
2247 | 2247 | ||
@@ -2291,7 +2291,7 @@ static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint3 | |||
2291 | bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS; | 2291 | bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS; |
2292 | } else | 2292 | } else |
2293 | bitmask[0] = bitmask[1] = 0; | 2293 | bitmask[0] = bitmask[1] = 0; |
2294 | dprintk("%s: bitmask=0x%x%x\n", __FUNCTION__, bitmask[0], bitmask[1]); | 2294 | dprintk("%s: bitmask=%08x:%08x\n", __func__, bitmask[0], bitmask[1]); |
2295 | return 0; | 2295 | return 0; |
2296 | } | 2296 | } |
2297 | 2297 | ||
@@ -3005,6 +3005,8 @@ static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res) | |||
3005 | int status; | 3005 | int status; |
3006 | 3006 | ||
3007 | status = decode_op_hdr(xdr, OP_CLOSE); | 3007 | status = decode_op_hdr(xdr, OP_CLOSE); |
3008 | if (status != -EIO) | ||
3009 | nfs_increment_open_seqid(status, res->seqid); | ||
3008 | if (status) | 3010 | if (status) |
3009 | return status; | 3011 | return status; |
3010 | READ_BUF(NFS4_STATEID_SIZE); | 3012 | READ_BUF(NFS4_STATEID_SIZE); |
@@ -3296,11 +3298,17 @@ static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res) | |||
3296 | int status; | 3298 | int status; |
3297 | 3299 | ||
3298 | status = decode_op_hdr(xdr, OP_LOCK); | 3300 | status = decode_op_hdr(xdr, OP_LOCK); |
3301 | if (status == -EIO) | ||
3302 | goto out; | ||
3299 | if (status == 0) { | 3303 | if (status == 0) { |
3300 | READ_BUF(NFS4_STATEID_SIZE); | 3304 | READ_BUF(NFS4_STATEID_SIZE); |
3301 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); | 3305 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); |
3302 | } else if (status == -NFS4ERR_DENIED) | 3306 | } else if (status == -NFS4ERR_DENIED) |
3303 | return decode_lock_denied(xdr, NULL); | 3307 | status = decode_lock_denied(xdr, NULL); |
3308 | if (res->open_seqid != NULL) | ||
3309 | nfs_increment_open_seqid(status, res->open_seqid); | ||
3310 | nfs_increment_lock_seqid(status, res->lock_seqid); | ||
3311 | out: | ||
3304 | return status; | 3312 | return status; |
3305 | } | 3313 | } |
3306 | 3314 | ||
@@ -3319,6 +3327,8 @@ static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res) | |||
3319 | int status; | 3327 | int status; |
3320 | 3328 | ||
3321 | status = decode_op_hdr(xdr, OP_LOCKU); | 3329 | status = decode_op_hdr(xdr, OP_LOCKU); |
3330 | if (status != -EIO) | ||
3331 | nfs_increment_lock_seqid(status, res->seqid); | ||
3322 | if (status == 0) { | 3332 | if (status == 0) { |
3323 | READ_BUF(NFS4_STATEID_SIZE); | 3333 | READ_BUF(NFS4_STATEID_SIZE); |
3324 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); | 3334 | COPYMEM(res->stateid.data, NFS4_STATEID_SIZE); |
@@ -3384,6 +3394,8 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) | |||
3384 | int status; | 3394 | int status; |
3385 | 3395 | ||
3386 | status = decode_op_hdr(xdr, OP_OPEN); | 3396 | status = decode_op_hdr(xdr, OP_OPEN); |
3397 | if (status != -EIO) | ||
3398 | nfs_increment_open_seqid(status, res->seqid); | ||
3387 | if (status) | 3399 | if (status) |
3388 | return status; | 3400 | return status; |
3389 | READ_BUF(NFS4_STATEID_SIZE); | 3401 | READ_BUF(NFS4_STATEID_SIZE); |
@@ -3416,6 +3428,8 @@ static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmre | |||
3416 | int status; | 3428 | int status; |
3417 | 3429 | ||
3418 | status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); | 3430 | status = decode_op_hdr(xdr, OP_OPEN_CONFIRM); |
3431 | if (status != -EIO) | ||
3432 | nfs_increment_open_seqid(status, res->seqid); | ||
3419 | if (status) | 3433 | if (status) |
3420 | return status; | 3434 | return status; |
3421 | READ_BUF(NFS4_STATEID_SIZE); | 3435 | READ_BUF(NFS4_STATEID_SIZE); |
@@ -3429,6 +3443,8 @@ static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *re | |||
3429 | int status; | 3443 | int status; |
3430 | 3444 | ||
3431 | status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE); | 3445 | status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE); |
3446 | if (status != -EIO) | ||
3447 | nfs_increment_open_seqid(status, res->seqid); | ||
3432 | if (status) | 3448 | if (status) |
3433 | return status; | 3449 | return status; |
3434 | READ_BUF(NFS4_STATEID_SIZE); | 3450 | READ_BUF(NFS4_STATEID_SIZE); |
@@ -3481,7 +3497,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3481 | size_t hdrlen; | 3497 | size_t hdrlen; |
3482 | u32 recvd, pglen = rcvbuf->page_len; | 3498 | u32 recvd, pglen = rcvbuf->page_len; |
3483 | __be32 *end, *entry, *p, *kaddr; | 3499 | __be32 *end, *entry, *p, *kaddr; |
3484 | unsigned int nr; | 3500 | unsigned int nr = 0; |
3485 | int status; | 3501 | int status; |
3486 | 3502 | ||
3487 | status = decode_op_hdr(xdr, OP_READDIR); | 3503 | status = decode_op_hdr(xdr, OP_READDIR); |
@@ -3489,8 +3505,8 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3489 | return status; | 3505 | return status; |
3490 | READ_BUF(8); | 3506 | READ_BUF(8); |
3491 | COPYMEM(readdir->verifier.data, 8); | 3507 | COPYMEM(readdir->verifier.data, 8); |
3492 | dprintk("%s: verifier = 0x%x%x\n", | 3508 | dprintk("%s: verifier = %08x:%08x\n", |
3493 | __FUNCTION__, | 3509 | __func__, |
3494 | ((u32 *)readdir->verifier.data)[0], | 3510 | ((u32 *)readdir->verifier.data)[0], |
3495 | ((u32 *)readdir->verifier.data)[1]); | 3511 | ((u32 *)readdir->verifier.data)[1]); |
3496 | 3512 | ||
@@ -3505,7 +3521,12 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3505 | kaddr = p = kmap_atomic(page, KM_USER0); | 3521 | kaddr = p = kmap_atomic(page, KM_USER0); |
3506 | end = p + ((pglen + readdir->pgbase) >> 2); | 3522 | end = p + ((pglen + readdir->pgbase) >> 2); |
3507 | entry = p; | 3523 | entry = p; |
3508 | for (nr = 0; *p++; nr++) { | 3524 | |
3525 | /* Make sure the packet actually has a value_follows and EOF entry */ | ||
3526 | if ((entry + 1) > end) | ||
3527 | goto short_pkt; | ||
3528 | |||
3529 | for (; *p++; nr++) { | ||
3509 | u32 len, attrlen, xlen; | 3530 | u32 len, attrlen, xlen; |
3510 | if (end - p < 3) | 3531 | if (end - p < 3) |
3511 | goto short_pkt; | 3532 | goto short_pkt; |
@@ -3532,20 +3553,32 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n | |||
3532 | p += attrlen; /* attributes */ | 3553 | p += attrlen; /* attributes */ |
3533 | entry = p; | 3554 | entry = p; |
3534 | } | 3555 | } |
3535 | if (!nr && (entry[0] != 0 || entry[1] == 0)) | 3556 | /* |
3536 | goto short_pkt; | 3557 | * Apparently some server sends responses that are a valid size, but |
3558 | * contain no entries, and have value_follows==0 and EOF==0. For | ||
3559 | * those, just set the EOF marker. | ||
3560 | */ | ||
3561 | if (!nr && entry[1] == 0) { | ||
3562 | dprintk("NFS: readdir reply truncated!\n"); | ||
3563 | entry[1] = 1; | ||
3564 | } | ||
3537 | out: | 3565 | out: |
3538 | kunmap_atomic(kaddr, KM_USER0); | 3566 | kunmap_atomic(kaddr, KM_USER0); |
3539 | return 0; | 3567 | return 0; |
3540 | short_pkt: | 3568 | short_pkt: |
3569 | /* | ||
3570 | * When we get a short packet there are 2 possibilities. We can | ||
3571 | * return an error, or fix up the response to look like a valid | ||
3572 | * response and return what we have so far. If there are no | ||
3573 | * entries and the packet was short, then return -EIO. If there | ||
3574 | * are valid entries in the response, return them and pretend that | ||
3575 | * the call was successful, but incomplete. The caller can retry the | ||
3576 | * readdir starting at the last cookie. | ||
3577 | */ | ||
3541 | dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr); | 3578 | dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr); |
3542 | entry[0] = entry[1] = 0; | 3579 | entry[0] = entry[1] = 0; |
3543 | /* truncate listing ? */ | 3580 | if (nr) |
3544 | if (!nr) { | 3581 | goto out; |
3545 | dprintk("NFS: readdir reply truncated!\n"); | ||
3546 | entry[1] = 1; | ||
3547 | } | ||
3548 | goto out; | ||
3549 | err_unmap: | 3582 | err_unmap: |
3550 | kunmap_atomic(kaddr, KM_USER0); | 3583 | kunmap_atomic(kaddr, KM_USER0); |
3551 | return -errno_NFSERR_IO; | 3584 | return -errno_NFSERR_IO; |
@@ -3727,7 +3760,7 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) | |||
3727 | READ_BUF(len); | 3760 | READ_BUF(len); |
3728 | return -NFSERR_CLID_INUSE; | 3761 | return -NFSERR_CLID_INUSE; |
3729 | } else | 3762 | } else |
3730 | return -nfs4_stat_to_errno(nfserr); | 3763 | return nfs4_stat_to_errno(nfserr); |
3731 | 3764 | ||
3732 | return 0; | 3765 | return 0; |
3733 | } | 3766 | } |
@@ -4389,7 +4422,7 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinf | |||
4389 | if (!status) | 4422 | if (!status) |
4390 | status = decode_fsinfo(&xdr, fsinfo); | 4423 | status = decode_fsinfo(&xdr, fsinfo); |
4391 | if (!status) | 4424 | if (!status) |
4392 | status = -nfs4_stat_to_errno(hdr.status); | 4425 | status = nfs4_stat_to_errno(hdr.status); |
4393 | return status; | 4426 | return status; |
4394 | } | 4427 | } |
4395 | 4428 | ||
@@ -4479,7 +4512,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, | |||
4479 | if (!status) | 4512 | if (!status) |
4480 | status = decode_setclientid(&xdr, clp); | 4513 | status = decode_setclientid(&xdr, clp); |
4481 | if (!status) | 4514 | if (!status) |
4482 | status = -nfs4_stat_to_errno(hdr.status); | 4515 | status = nfs4_stat_to_errno(hdr.status); |
4483 | return status; | 4516 | return status; |
4484 | } | 4517 | } |
4485 | 4518 | ||
@@ -4501,7 +4534,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str | |||
4501 | if (!status) | 4534 | if (!status) |
4502 | status = decode_fsinfo(&xdr, fsinfo); | 4535 | status = decode_fsinfo(&xdr, fsinfo); |
4503 | if (!status) | 4536 | if (!status) |
4504 | status = -nfs4_stat_to_errno(hdr.status); | 4537 | status = nfs4_stat_to_errno(hdr.status); |
4505 | return status; | 4538 | return status; |
4506 | } | 4539 | } |
4507 | 4540 | ||
@@ -4611,42 +4644,42 @@ static struct { | |||
4611 | int errno; | 4644 | int errno; |
4612 | } nfs_errtbl[] = { | 4645 | } nfs_errtbl[] = { |
4613 | { NFS4_OK, 0 }, | 4646 | { NFS4_OK, 0 }, |
4614 | { NFS4ERR_PERM, EPERM }, | 4647 | { NFS4ERR_PERM, -EPERM }, |
4615 | { NFS4ERR_NOENT, ENOENT }, | 4648 | { NFS4ERR_NOENT, -ENOENT }, |
4616 | { NFS4ERR_IO, errno_NFSERR_IO }, | 4649 | { NFS4ERR_IO, -errno_NFSERR_IO}, |
4617 | { NFS4ERR_NXIO, ENXIO }, | 4650 | { NFS4ERR_NXIO, -ENXIO }, |
4618 | { NFS4ERR_ACCESS, EACCES }, | 4651 | { NFS4ERR_ACCESS, -EACCES }, |
4619 | { NFS4ERR_EXIST, EEXIST }, | 4652 | { NFS4ERR_EXIST, -EEXIST }, |
4620 | { NFS4ERR_XDEV, EXDEV }, | 4653 | { NFS4ERR_XDEV, -EXDEV }, |
4621 | { NFS4ERR_NOTDIR, ENOTDIR }, | 4654 | { NFS4ERR_NOTDIR, -ENOTDIR }, |
4622 | { NFS4ERR_ISDIR, EISDIR }, | 4655 | { NFS4ERR_ISDIR, -EISDIR }, |
4623 | { NFS4ERR_INVAL, EINVAL }, | 4656 | { NFS4ERR_INVAL, -EINVAL }, |
4624 | { NFS4ERR_FBIG, EFBIG }, | 4657 | { NFS4ERR_FBIG, -EFBIG }, |
4625 | { NFS4ERR_NOSPC, ENOSPC }, | 4658 | { NFS4ERR_NOSPC, -ENOSPC }, |
4626 | { NFS4ERR_ROFS, EROFS }, | 4659 | { NFS4ERR_ROFS, -EROFS }, |
4627 | { NFS4ERR_MLINK, EMLINK }, | 4660 | { NFS4ERR_MLINK, -EMLINK }, |
4628 | { NFS4ERR_NAMETOOLONG, ENAMETOOLONG }, | 4661 | { NFS4ERR_NAMETOOLONG, -ENAMETOOLONG }, |
4629 | { NFS4ERR_NOTEMPTY, ENOTEMPTY }, | 4662 | { NFS4ERR_NOTEMPTY, -ENOTEMPTY }, |
4630 | { NFS4ERR_DQUOT, EDQUOT }, | 4663 | { NFS4ERR_DQUOT, -EDQUOT }, |
4631 | { NFS4ERR_STALE, ESTALE }, | 4664 | { NFS4ERR_STALE, -ESTALE }, |
4632 | { NFS4ERR_BADHANDLE, EBADHANDLE }, | 4665 | { NFS4ERR_BADHANDLE, -EBADHANDLE }, |
4633 | { NFS4ERR_BADOWNER, EINVAL }, | 4666 | { NFS4ERR_BADOWNER, -EINVAL }, |
4634 | { NFS4ERR_BADNAME, EINVAL }, | 4667 | { NFS4ERR_BADNAME, -EINVAL }, |
4635 | { NFS4ERR_BAD_COOKIE, EBADCOOKIE }, | 4668 | { NFS4ERR_BAD_COOKIE, -EBADCOOKIE }, |
4636 | { NFS4ERR_NOTSUPP, ENOTSUPP }, | 4669 | { NFS4ERR_NOTSUPP, -ENOTSUPP }, |
4637 | { NFS4ERR_TOOSMALL, ETOOSMALL }, | 4670 | { NFS4ERR_TOOSMALL, -ETOOSMALL }, |
4638 | { NFS4ERR_SERVERFAULT, ESERVERFAULT }, | 4671 | { NFS4ERR_SERVERFAULT, -ESERVERFAULT }, |
4639 | { NFS4ERR_BADTYPE, EBADTYPE }, | 4672 | { NFS4ERR_BADTYPE, -EBADTYPE }, |
4640 | { NFS4ERR_LOCKED, EAGAIN }, | 4673 | { NFS4ERR_LOCKED, -EAGAIN }, |
4641 | { NFS4ERR_RESOURCE, EREMOTEIO }, | 4674 | { NFS4ERR_RESOURCE, -EREMOTEIO }, |
4642 | { NFS4ERR_SYMLINK, ELOOP }, | 4675 | { NFS4ERR_SYMLINK, -ELOOP }, |
4643 | { NFS4ERR_OP_ILLEGAL, EOPNOTSUPP }, | 4676 | { NFS4ERR_OP_ILLEGAL, -EOPNOTSUPP }, |
4644 | { NFS4ERR_DEADLOCK, EDEADLK }, | 4677 | { NFS4ERR_DEADLOCK, -EDEADLK }, |
4645 | { NFS4ERR_WRONGSEC, EPERM }, /* FIXME: this needs | 4678 | { NFS4ERR_WRONGSEC, -EPERM }, /* FIXME: this needs |
4646 | * to be handled by a | 4679 | * to be handled by a |
4647 | * middle-layer. | 4680 | * middle-layer. |
4648 | */ | 4681 | */ |
4649 | { -1, EIO } | 4682 | { -1, -EIO } |
4650 | }; | 4683 | }; |
4651 | 4684 | ||
4652 | /* | 4685 | /* |
@@ -4663,14 +4696,14 @@ nfs4_stat_to_errno(int stat) | |||
4663 | } | 4696 | } |
4664 | if (stat <= 10000 || stat > 10100) { | 4697 | if (stat <= 10000 || stat > 10100) { |
4665 | /* The server is looney tunes. */ | 4698 | /* The server is looney tunes. */ |
4666 | return ESERVERFAULT; | 4699 | return -ESERVERFAULT; |
4667 | } | 4700 | } |
4668 | /* If we cannot translate the error, the recovery routines should | 4701 | /* If we cannot translate the error, the recovery routines should |
4669 | * handle it. | 4702 | * handle it. |
4670 | * Note: remaining NFSv4 error codes have values > 10000, so should | 4703 | * Note: remaining NFSv4 error codes have values > 10000, so should |
4671 | * not conflict with native Linux error codes. | 4704 | * not conflict with native Linux error codes. |
4672 | */ | 4705 | */ |
4673 | return stat; | 4706 | return -stat; |
4674 | } | 4707 | } |
4675 | 4708 | ||
4676 | #define PROC(proc, argtype, restype) \ | 4709 | #define PROC(proc, argtype, restype) \ |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 5a70be589bbe..16f57e0af999 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -58,22 +58,19 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | |||
58 | return p; | 58 | return p; |
59 | } | 59 | } |
60 | 60 | ||
61 | static void nfs_readdata_rcu_free(struct rcu_head *head) | 61 | static void nfs_readdata_free(struct nfs_read_data *p) |
62 | { | 62 | { |
63 | struct nfs_read_data *p = container_of(head, struct nfs_read_data, task.u.tk_rcu); | ||
64 | if (p && (p->pagevec != &p->page_array[0])) | 63 | if (p && (p->pagevec != &p->page_array[0])) |
65 | kfree(p->pagevec); | 64 | kfree(p->pagevec); |
66 | mempool_free(p, nfs_rdata_mempool); | 65 | mempool_free(p, nfs_rdata_mempool); |
67 | } | 66 | } |
68 | 67 | ||
69 | static void nfs_readdata_free(struct nfs_read_data *rdata) | ||
70 | { | ||
71 | call_rcu_bh(&rdata->task.u.tk_rcu, nfs_readdata_rcu_free); | ||
72 | } | ||
73 | |||
74 | void nfs_readdata_release(void *data) | 68 | void nfs_readdata_release(void *data) |
75 | { | 69 | { |
76 | nfs_readdata_free(data); | 70 | struct nfs_read_data *rdata = data; |
71 | |||
72 | put_nfs_open_context(rdata->args.context); | ||
73 | nfs_readdata_free(rdata); | ||
77 | } | 74 | } |
78 | 75 | ||
79 | static | 76 | static |
@@ -156,7 +153,7 @@ static void nfs_readpage_release(struct nfs_page *req) | |||
156 | /* | 153 | /* |
157 | * Set up the NFS read request struct | 154 | * Set up the NFS read request struct |
158 | */ | 155 | */ |
159 | static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | 156 | static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, |
160 | const struct rpc_call_ops *call_ops, | 157 | const struct rpc_call_ops *call_ops, |
161 | unsigned int count, unsigned int offset) | 158 | unsigned int count, unsigned int offset) |
162 | { | 159 | { |
@@ -174,6 +171,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
174 | .rpc_message = &msg, | 171 | .rpc_message = &msg, |
175 | .callback_ops = call_ops, | 172 | .callback_ops = call_ops, |
176 | .callback_data = data, | 173 | .callback_data = data, |
174 | .workqueue = nfsiod_workqueue, | ||
177 | .flags = RPC_TASK_ASYNC | swap_flags, | 175 | .flags = RPC_TASK_ASYNC | swap_flags, |
178 | }; | 176 | }; |
179 | 177 | ||
@@ -186,7 +184,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
186 | data->args.pgbase = req->wb_pgbase + offset; | 184 | data->args.pgbase = req->wb_pgbase + offset; |
187 | data->args.pages = data->pagevec; | 185 | data->args.pages = data->pagevec; |
188 | data->args.count = count; | 186 | data->args.count = count; |
189 | data->args.context = req->wb_context; | 187 | data->args.context = get_nfs_open_context(req->wb_context); |
190 | 188 | ||
191 | data->res.fattr = &data->fattr; | 189 | data->res.fattr = &data->fattr; |
192 | data->res.count = count; | 190 | data->res.count = count; |
@@ -204,8 +202,10 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
204 | (unsigned long long)data->args.offset); | 202 | (unsigned long long)data->args.offset); |
205 | 203 | ||
206 | task = rpc_run_task(&task_setup_data); | 204 | task = rpc_run_task(&task_setup_data); |
207 | if (!IS_ERR(task)) | 205 | if (IS_ERR(task)) |
208 | rpc_put_task(task); | 206 | return PTR_ERR(task); |
207 | rpc_put_task(task); | ||
208 | return 0; | ||
209 | } | 209 | } |
210 | 210 | ||
211 | static void | 211 | static void |
@@ -242,6 +242,7 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
242 | size_t rsize = NFS_SERVER(inode)->rsize, nbytes; | 242 | size_t rsize = NFS_SERVER(inode)->rsize, nbytes; |
243 | unsigned int offset; | 243 | unsigned int offset; |
244 | int requests = 0; | 244 | int requests = 0; |
245 | int ret = 0; | ||
245 | LIST_HEAD(list); | 246 | LIST_HEAD(list); |
246 | 247 | ||
247 | nfs_list_remove_request(req); | 248 | nfs_list_remove_request(req); |
@@ -253,7 +254,6 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
253 | data = nfs_readdata_alloc(1); | 254 | data = nfs_readdata_alloc(1); |
254 | if (!data) | 255 | if (!data) |
255 | goto out_bad; | 256 | goto out_bad; |
256 | INIT_LIST_HEAD(&data->pages); | ||
257 | list_add(&data->pages, &list); | 257 | list_add(&data->pages, &list); |
258 | requests++; | 258 | requests++; |
259 | nbytes -= len; | 259 | nbytes -= len; |
@@ -264,6 +264,8 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
264 | offset = 0; | 264 | offset = 0; |
265 | nbytes = count; | 265 | nbytes = count; |
266 | do { | 266 | do { |
267 | int ret2; | ||
268 | |||
267 | data = list_entry(list.next, struct nfs_read_data, pages); | 269 | data = list_entry(list.next, struct nfs_read_data, pages); |
268 | list_del_init(&data->pages); | 270 | list_del_init(&data->pages); |
269 | 271 | ||
@@ -271,13 +273,15 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne | |||
271 | 273 | ||
272 | if (nbytes < rsize) | 274 | if (nbytes < rsize) |
273 | rsize = nbytes; | 275 | rsize = nbytes; |
274 | nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, | 276 | ret2 = nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, |
275 | rsize, offset); | 277 | rsize, offset); |
278 | if (ret == 0) | ||
279 | ret = ret2; | ||
276 | offset += rsize; | 280 | offset += rsize; |
277 | nbytes -= rsize; | 281 | nbytes -= rsize; |
278 | } while (nbytes != 0); | 282 | } while (nbytes != 0); |
279 | 283 | ||
280 | return 0; | 284 | return ret; |
281 | 285 | ||
282 | out_bad: | 286 | out_bad: |
283 | while (!list_empty(&list)) { | 287 | while (!list_empty(&list)) { |
@@ -295,12 +299,12 @@ static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned | |||
295 | struct nfs_page *req; | 299 | struct nfs_page *req; |
296 | struct page **pages; | 300 | struct page **pages; |
297 | struct nfs_read_data *data; | 301 | struct nfs_read_data *data; |
302 | int ret = -ENOMEM; | ||
298 | 303 | ||
299 | data = nfs_readdata_alloc(npages); | 304 | data = nfs_readdata_alloc(npages); |
300 | if (!data) | 305 | if (!data) |
301 | goto out_bad; | 306 | goto out_bad; |
302 | 307 | ||
303 | INIT_LIST_HEAD(&data->pages); | ||
304 | pages = data->pagevec; | 308 | pages = data->pagevec; |
305 | while (!list_empty(head)) { | 309 | while (!list_empty(head)) { |
306 | req = nfs_list_entry(head->next); | 310 | req = nfs_list_entry(head->next); |
@@ -311,11 +315,10 @@ static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned | |||
311 | } | 315 | } |
312 | req = nfs_list_entry(data->pages.next); | 316 | req = nfs_list_entry(data->pages.next); |
313 | 317 | ||
314 | nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); | 318 | return nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0); |
315 | return 0; | ||
316 | out_bad: | 319 | out_bad: |
317 | nfs_async_read_error(head); | 320 | nfs_async_read_error(head); |
318 | return -ENOMEM; | 321 | return ret; |
319 | } | 322 | } |
320 | 323 | ||
321 | /* | 324 | /* |
@@ -342,26 +345,25 @@ int nfs_readpage_result(struct rpc_task *task, struct nfs_read_data *data) | |||
342 | return 0; | 345 | return 0; |
343 | } | 346 | } |
344 | 347 | ||
345 | static int nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) | 348 | static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) |
346 | { | 349 | { |
347 | struct nfs_readargs *argp = &data->args; | 350 | struct nfs_readargs *argp = &data->args; |
348 | struct nfs_readres *resp = &data->res; | 351 | struct nfs_readres *resp = &data->res; |
349 | 352 | ||
350 | if (resp->eof || resp->count == argp->count) | 353 | if (resp->eof || resp->count == argp->count) |
351 | return 0; | 354 | return; |
352 | 355 | ||
353 | /* This is a short read! */ | 356 | /* This is a short read! */ |
354 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | 357 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); |
355 | /* Has the server at least made some progress? */ | 358 | /* Has the server at least made some progress? */ |
356 | if (resp->count == 0) | 359 | if (resp->count == 0) |
357 | return 0; | 360 | return; |
358 | 361 | ||
359 | /* Yes, so retry the read at the end of the data */ | 362 | /* Yes, so retry the read at the end of the data */ |
360 | argp->offset += resp->count; | 363 | argp->offset += resp->count; |
361 | argp->pgbase += resp->count; | 364 | argp->pgbase += resp->count; |
362 | argp->count -= resp->count; | 365 | argp->count -= resp->count; |
363 | rpc_restart_call(task); | 366 | rpc_restart_call(task); |
364 | return -EAGAIN; | ||
365 | } | 367 | } |
366 | 368 | ||
367 | /* | 369 | /* |
@@ -370,29 +372,37 @@ static int nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data) | |||
370 | static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) | 372 | static void nfs_readpage_result_partial(struct rpc_task *task, void *calldata) |
371 | { | 373 | { |
372 | struct nfs_read_data *data = calldata; | 374 | struct nfs_read_data *data = calldata; |
373 | struct nfs_page *req = data->req; | ||
374 | struct page *page = req->wb_page; | ||
375 | 375 | ||
376 | if (nfs_readpage_result(task, data) != 0) | 376 | if (nfs_readpage_result(task, data) != 0) |
377 | return; | 377 | return; |
378 | if (task->tk_status < 0) | ||
379 | return; | ||
378 | 380 | ||
379 | if (likely(task->tk_status >= 0)) { | 381 | nfs_readpage_truncate_uninitialised_page(data); |
380 | nfs_readpage_truncate_uninitialised_page(data); | 382 | nfs_readpage_retry(task, data); |
381 | if (nfs_readpage_retry(task, data) != 0) | 383 | } |
382 | return; | 384 | |
383 | } | 385 | static void nfs_readpage_release_partial(void *calldata) |
384 | if (unlikely(task->tk_status < 0)) | 386 | { |
387 | struct nfs_read_data *data = calldata; | ||
388 | struct nfs_page *req = data->req; | ||
389 | struct page *page = req->wb_page; | ||
390 | int status = data->task.tk_status; | ||
391 | |||
392 | if (status < 0) | ||
385 | SetPageError(page); | 393 | SetPageError(page); |
394 | |||
386 | if (atomic_dec_and_test(&req->wb_complete)) { | 395 | if (atomic_dec_and_test(&req->wb_complete)) { |
387 | if (!PageError(page)) | 396 | if (!PageError(page)) |
388 | SetPageUptodate(page); | 397 | SetPageUptodate(page); |
389 | nfs_readpage_release(req); | 398 | nfs_readpage_release(req); |
390 | } | 399 | } |
400 | nfs_readdata_release(calldata); | ||
391 | } | 401 | } |
392 | 402 | ||
393 | static const struct rpc_call_ops nfs_read_partial_ops = { | 403 | static const struct rpc_call_ops nfs_read_partial_ops = { |
394 | .rpc_call_done = nfs_readpage_result_partial, | 404 | .rpc_call_done = nfs_readpage_result_partial, |
395 | .rpc_release = nfs_readdata_release, | 405 | .rpc_release = nfs_readpage_release_partial, |
396 | }; | 406 | }; |
397 | 407 | ||
398 | static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) | 408 | static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) |
@@ -427,29 +437,35 @@ static void nfs_readpage_result_full(struct rpc_task *task, void *calldata) | |||
427 | 437 | ||
428 | if (nfs_readpage_result(task, data) != 0) | 438 | if (nfs_readpage_result(task, data) != 0) |
429 | return; | 439 | return; |
440 | if (task->tk_status < 0) | ||
441 | return; | ||
430 | /* | 442 | /* |
431 | * Note: nfs_readpage_retry may change the values of | 443 | * Note: nfs_readpage_retry may change the values of |
432 | * data->args. In the multi-page case, we therefore need | 444 | * data->args. In the multi-page case, we therefore need |
433 | * to ensure that we call nfs_readpage_set_pages_uptodate() | 445 | * to ensure that we call nfs_readpage_set_pages_uptodate() |
434 | * first. | 446 | * first. |
435 | */ | 447 | */ |
436 | if (likely(task->tk_status >= 0)) { | 448 | nfs_readpage_truncate_uninitialised_page(data); |
437 | nfs_readpage_truncate_uninitialised_page(data); | 449 | nfs_readpage_set_pages_uptodate(data); |
438 | nfs_readpage_set_pages_uptodate(data); | 450 | nfs_readpage_retry(task, data); |
439 | if (nfs_readpage_retry(task, data) != 0) | 451 | } |
440 | return; | 452 | |
441 | } | 453 | static void nfs_readpage_release_full(void *calldata) |
454 | { | ||
455 | struct nfs_read_data *data = calldata; | ||
456 | |||
442 | while (!list_empty(&data->pages)) { | 457 | while (!list_empty(&data->pages)) { |
443 | struct nfs_page *req = nfs_list_entry(data->pages.next); | 458 | struct nfs_page *req = nfs_list_entry(data->pages.next); |
444 | 459 | ||
445 | nfs_list_remove_request(req); | 460 | nfs_list_remove_request(req); |
446 | nfs_readpage_release(req); | 461 | nfs_readpage_release(req); |
447 | } | 462 | } |
463 | nfs_readdata_release(calldata); | ||
448 | } | 464 | } |
449 | 465 | ||
450 | static const struct rpc_call_ops nfs_read_full_ops = { | 466 | static const struct rpc_call_ops nfs_read_full_ops = { |
451 | .rpc_call_done = nfs_readpage_result_full, | 467 | .rpc_call_done = nfs_readpage_result_full, |
452 | .rpc_release = nfs_readdata_release, | 468 | .rpc_release = nfs_readpage_release_full, |
453 | }; | 469 | }; |
454 | 470 | ||
455 | /* | 471 | /* |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index f9219024f31a..fa220dc74609 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -198,7 +198,7 @@ static match_table_t nfs_secflavor_tokens = { | |||
198 | }; | 198 | }; |
199 | 199 | ||
200 | 200 | ||
201 | static void nfs_umount_begin(struct vfsmount *, int); | 201 | static void nfs_umount_begin(struct super_block *); |
202 | static int nfs_statfs(struct dentry *, struct kstatfs *); | 202 | static int nfs_statfs(struct dentry *, struct kstatfs *); |
203 | static int nfs_show_options(struct seq_file *, struct vfsmount *); | 203 | static int nfs_show_options(struct seq_file *, struct vfsmount *); |
204 | static int nfs_show_stats(struct seq_file *, struct vfsmount *); | 204 | static int nfs_show_stats(struct seq_file *, struct vfsmount *); |
@@ -441,10 +441,52 @@ static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour) | |||
441 | return sec_flavours[i].str; | 441 | return sec_flavours[i].str; |
442 | } | 442 | } |
443 | 443 | ||
444 | static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss, | ||
445 | int showdefaults) | ||
446 | { | ||
447 | struct sockaddr *sap = (struct sockaddr *)&nfss->mountd_address; | ||
448 | |||
449 | switch (sap->sa_family) { | ||
450 | case AF_INET: { | ||
451 | struct sockaddr_in *sin = (struct sockaddr_in *)sap; | ||
452 | seq_printf(m, ",mountaddr=" NIPQUAD_FMT, | ||
453 | NIPQUAD(sin->sin_addr.s_addr)); | ||
454 | break; | ||
455 | } | ||
456 | case AF_INET6: { | ||
457 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | ||
458 | seq_printf(m, ",mountaddr=" NIP6_FMT, | ||
459 | NIP6(sin6->sin6_addr)); | ||
460 | break; | ||
461 | } | ||
462 | default: | ||
463 | if (showdefaults) | ||
464 | seq_printf(m, ",mountaddr=unspecified"); | ||
465 | } | ||
466 | |||
467 | if (nfss->mountd_version || showdefaults) | ||
468 | seq_printf(m, ",mountvers=%u", nfss->mountd_version); | ||
469 | if (nfss->mountd_port || showdefaults) | ||
470 | seq_printf(m, ",mountport=%u", nfss->mountd_port); | ||
471 | |||
472 | switch (nfss->mountd_protocol) { | ||
473 | case IPPROTO_UDP: | ||
474 | seq_printf(m, ",mountproto=udp"); | ||
475 | break; | ||
476 | case IPPROTO_TCP: | ||
477 | seq_printf(m, ",mountproto=tcp"); | ||
478 | break; | ||
479 | default: | ||
480 | if (showdefaults) | ||
481 | seq_printf(m, ",mountproto=auto"); | ||
482 | } | ||
483 | } | ||
484 | |||
444 | /* | 485 | /* |
445 | * Describe the mount options in force on this server representation | 486 | * Describe the mount options in force on this server representation |
446 | */ | 487 | */ |
447 | static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults) | 488 | static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, |
489 | int showdefaults) | ||
448 | { | 490 | { |
449 | static const struct proc_nfs_info { | 491 | static const struct proc_nfs_info { |
450 | int flag; | 492 | int flag; |
@@ -452,6 +494,8 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
452 | const char *nostr; | 494 | const char *nostr; |
453 | } nfs_info[] = { | 495 | } nfs_info[] = { |
454 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, | 496 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, |
497 | { NFS_MOUNT_INTR, ",intr", ",nointr" }, | ||
498 | { NFS_MOUNT_POSIX, ",posix", "" }, | ||
455 | { NFS_MOUNT_NOCTO, ",nocto", "" }, | 499 | { NFS_MOUNT_NOCTO, ",nocto", "" }, |
456 | { NFS_MOUNT_NOAC, ",noac", "" }, | 500 | { NFS_MOUNT_NOAC, ",noac", "" }, |
457 | { NFS_MOUNT_NONLM, ",nolock", "" }, | 501 | { NFS_MOUNT_NONLM, ",nolock", "" }, |
@@ -462,18 +506,22 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
462 | }; | 506 | }; |
463 | const struct proc_nfs_info *nfs_infop; | 507 | const struct proc_nfs_info *nfs_infop; |
464 | struct nfs_client *clp = nfss->nfs_client; | 508 | struct nfs_client *clp = nfss->nfs_client; |
465 | 509 | u32 version = clp->rpc_ops->version; | |
466 | seq_printf(m, ",vers=%d", clp->rpc_ops->version); | 510 | |
467 | seq_printf(m, ",rsize=%d", nfss->rsize); | 511 | seq_printf(m, ",vers=%u", version); |
468 | seq_printf(m, ",wsize=%d", nfss->wsize); | 512 | seq_printf(m, ",rsize=%u", nfss->rsize); |
513 | seq_printf(m, ",wsize=%u", nfss->wsize); | ||
514 | if (nfss->bsize != 0) | ||
515 | seq_printf(m, ",bsize=%u", nfss->bsize); | ||
516 | seq_printf(m, ",namlen=%u", nfss->namelen); | ||
469 | if (nfss->acregmin != 3*HZ || showdefaults) | 517 | if (nfss->acregmin != 3*HZ || showdefaults) |
470 | seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ); | 518 | seq_printf(m, ",acregmin=%u", nfss->acregmin/HZ); |
471 | if (nfss->acregmax != 60*HZ || showdefaults) | 519 | if (nfss->acregmax != 60*HZ || showdefaults) |
472 | seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ); | 520 | seq_printf(m, ",acregmax=%u", nfss->acregmax/HZ); |
473 | if (nfss->acdirmin != 30*HZ || showdefaults) | 521 | if (nfss->acdirmin != 30*HZ || showdefaults) |
474 | seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ); | 522 | seq_printf(m, ",acdirmin=%u", nfss->acdirmin/HZ); |
475 | if (nfss->acdirmax != 60*HZ || showdefaults) | 523 | if (nfss->acdirmax != 60*HZ || showdefaults) |
476 | seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ); | 524 | seq_printf(m, ",acdirmax=%u", nfss->acdirmax/HZ); |
477 | for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { | 525 | for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { |
478 | if (nfss->flags & nfs_infop->flag) | 526 | if (nfss->flags & nfs_infop->flag) |
479 | seq_puts(m, nfs_infop->str); | 527 | seq_puts(m, nfs_infop->str); |
@@ -482,9 +530,24 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
482 | } | 530 | } |
483 | seq_printf(m, ",proto=%s", | 531 | seq_printf(m, ",proto=%s", |
484 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO)); | 532 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO)); |
533 | if (version == 4) { | ||
534 | if (nfss->port != NFS_PORT) | ||
535 | seq_printf(m, ",port=%u", nfss->port); | ||
536 | } else | ||
537 | if (nfss->port) | ||
538 | seq_printf(m, ",port=%u", nfss->port); | ||
539 | |||
485 | seq_printf(m, ",timeo=%lu", 10U * nfss->client->cl_timeout->to_initval / HZ); | 540 | seq_printf(m, ",timeo=%lu", 10U * nfss->client->cl_timeout->to_initval / HZ); |
486 | seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries); | 541 | seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries); |
487 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); | 542 | seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor)); |
543 | |||
544 | if (version != 4) | ||
545 | nfs_show_mountd_options(m, nfss, showdefaults); | ||
546 | |||
547 | #ifdef CONFIG_NFS_V4 | ||
548 | if (clp->rpc_ops->version == 4) | ||
549 | seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr); | ||
550 | #endif | ||
488 | } | 551 | } |
489 | 552 | ||
490 | /* | 553 | /* |
@@ -529,10 +592,10 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
529 | 592 | ||
530 | seq_printf(m, "\n\tcaps:\t"); | 593 | seq_printf(m, "\n\tcaps:\t"); |
531 | seq_printf(m, "caps=0x%x", nfss->caps); | 594 | seq_printf(m, "caps=0x%x", nfss->caps); |
532 | seq_printf(m, ",wtmult=%d", nfss->wtmult); | 595 | seq_printf(m, ",wtmult=%u", nfss->wtmult); |
533 | seq_printf(m, ",dtsize=%d", nfss->dtsize); | 596 | seq_printf(m, ",dtsize=%u", nfss->dtsize); |
534 | seq_printf(m, ",bsize=%d", nfss->bsize); | 597 | seq_printf(m, ",bsize=%u", nfss->bsize); |
535 | seq_printf(m, ",namelen=%d", nfss->namelen); | 598 | seq_printf(m, ",namlen=%u", nfss->namelen); |
536 | 599 | ||
537 | #ifdef CONFIG_NFS_V4 | 600 | #ifdef CONFIG_NFS_V4 |
538 | if (nfss->nfs_client->rpc_ops->version == 4) { | 601 | if (nfss->nfs_client->rpc_ops->version == 4) { |
@@ -546,9 +609,9 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
546 | /* | 609 | /* |
547 | * Display security flavor in effect for this mount | 610 | * Display security flavor in effect for this mount |
548 | */ | 611 | */ |
549 | seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor); | 612 | seq_printf(m, "\n\tsec:\tflavor=%u", auth->au_ops->au_flavor); |
550 | if (auth->au_flavor) | 613 | if (auth->au_flavor) |
551 | seq_printf(m, ",pseudoflavor=%d", auth->au_flavor); | 614 | seq_printf(m, ",pseudoflavor=%u", auth->au_flavor); |
552 | 615 | ||
553 | /* | 616 | /* |
554 | * Display superblock I/O counters | 617 | * Display superblock I/O counters |
@@ -584,13 +647,11 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |||
584 | * Begin unmount by attempting to remove all automounted mountpoints we added | 647 | * Begin unmount by attempting to remove all automounted mountpoints we added |
585 | * in response to xdev traversals and referrals | 648 | * in response to xdev traversals and referrals |
586 | */ | 649 | */ |
587 | static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) | 650 | static void nfs_umount_begin(struct super_block *sb) |
588 | { | 651 | { |
589 | struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb); | 652 | struct nfs_server *server = NFS_SB(sb); |
590 | struct rpc_clnt *rpc; | 653 | struct rpc_clnt *rpc; |
591 | 654 | ||
592 | if (!(flags & MNT_FORCE)) | ||
593 | return; | ||
594 | /* -EIO all pending I/O */ | 655 | /* -EIO all pending I/O */ |
595 | rpc = server->client_acl; | 656 | rpc = server->client_acl; |
596 | if (!IS_ERR(rpc)) | 657 | if (!IS_ERR(rpc)) |
@@ -683,7 +744,6 @@ static int nfs_parse_mount_options(char *raw, | |||
683 | struct nfs_parsed_mount_data *mnt) | 744 | struct nfs_parsed_mount_data *mnt) |
684 | { | 745 | { |
685 | char *p, *string, *secdata; | 746 | char *p, *string, *secdata; |
686 | unsigned short port = 0; | ||
687 | int rc; | 747 | int rc; |
688 | 748 | ||
689 | if (!raw) { | 749 | if (!raw) { |
@@ -798,7 +858,7 @@ static int nfs_parse_mount_options(char *raw, | |||
798 | return 0; | 858 | return 0; |
799 | if (option < 0 || option > 65535) | 859 | if (option < 0 || option > 65535) |
800 | return 0; | 860 | return 0; |
801 | port = option; | 861 | mnt->nfs_server.port = option; |
802 | break; | 862 | break; |
803 | case Opt_rsize: | 863 | case Opt_rsize: |
804 | if (match_int(args, &mnt->rsize)) | 864 | if (match_int(args, &mnt->rsize)) |
@@ -1048,7 +1108,8 @@ static int nfs_parse_mount_options(char *raw, | |||
1048 | } | 1108 | } |
1049 | } | 1109 | } |
1050 | 1110 | ||
1051 | nfs_set_port((struct sockaddr *)&mnt->nfs_server.address, port); | 1111 | nfs_set_port((struct sockaddr *)&mnt->nfs_server.address, |
1112 | mnt->nfs_server.port); | ||
1052 | 1113 | ||
1053 | return 1; | 1114 | return 1; |
1054 | 1115 | ||
@@ -1169,7 +1230,9 @@ static int nfs_validate_mount_data(void *options, | |||
1169 | args->acregmax = 60; | 1230 | args->acregmax = 60; |
1170 | args->acdirmin = 30; | 1231 | args->acdirmin = 30; |
1171 | args->acdirmax = 60; | 1232 | args->acdirmax = 60; |
1233 | args->mount_server.port = 0; /* autobind unless user sets port */ | ||
1172 | args->mount_server.protocol = XPRT_TRANSPORT_UDP; | 1234 | args->mount_server.protocol = XPRT_TRANSPORT_UDP; |
1235 | args->nfs_server.port = 0; /* autobind unless user sets port */ | ||
1173 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1236 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1174 | 1237 | ||
1175 | switch (data->version) { | 1238 | switch (data->version) { |
@@ -1208,7 +1271,6 @@ static int nfs_validate_mount_data(void *options, | |||
1208 | args->flags = data->flags; | 1271 | args->flags = data->flags; |
1209 | args->rsize = data->rsize; | 1272 | args->rsize = data->rsize; |
1210 | args->wsize = data->wsize; | 1273 | args->wsize = data->wsize; |
1211 | args->flags = data->flags; | ||
1212 | args->timeo = data->timeo; | 1274 | args->timeo = data->timeo; |
1213 | args->retrans = data->retrans; | 1275 | args->retrans = data->retrans; |
1214 | args->acregmin = data->acregmin; | 1276 | args->acregmin = data->acregmin; |
@@ -1230,6 +1292,8 @@ static int nfs_validate_mount_data(void *options, | |||
1230 | args->namlen = data->namlen; | 1292 | args->namlen = data->namlen; |
1231 | args->bsize = data->bsize; | 1293 | args->bsize = data->bsize; |
1232 | args->auth_flavors[0] = data->pseudoflavor; | 1294 | args->auth_flavors[0] = data->pseudoflavor; |
1295 | if (!args->nfs_server.hostname) | ||
1296 | goto out_nomem; | ||
1233 | 1297 | ||
1234 | /* | 1298 | /* |
1235 | * The legacy version 6 binary mount data from userspace has a | 1299 | * The legacy version 6 binary mount data from userspace has a |
@@ -1276,6 +1340,8 @@ static int nfs_validate_mount_data(void *options, | |||
1276 | len = c - dev_name; | 1340 | len = c - dev_name; |
1277 | /* N.B. caller will free nfs_server.hostname in all cases */ | 1341 | /* N.B. caller will free nfs_server.hostname in all cases */ |
1278 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); | 1342 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); |
1343 | if (!args->nfs_server.hostname) | ||
1344 | goto out_nomem; | ||
1279 | 1345 | ||
1280 | c++; | 1346 | c++; |
1281 | if (strlen(c) > NFS_MAXPATHLEN) | 1347 | if (strlen(c) > NFS_MAXPATHLEN) |
@@ -1319,6 +1385,10 @@ out_v3_not_compiled: | |||
1319 | return -EPROTONOSUPPORT; | 1385 | return -EPROTONOSUPPORT; |
1320 | #endif /* !CONFIG_NFS_V3 */ | 1386 | #endif /* !CONFIG_NFS_V3 */ |
1321 | 1387 | ||
1388 | out_nomem: | ||
1389 | dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n"); | ||
1390 | return -ENOMEM; | ||
1391 | |||
1322 | out_no_address: | 1392 | out_no_address: |
1323 | dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); | 1393 | dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); |
1324 | return -EINVAL; | 1394 | return -EINVAL; |
@@ -1706,28 +1776,6 @@ static void nfs4_fill_super(struct super_block *sb) | |||
1706 | } | 1776 | } |
1707 | 1777 | ||
1708 | /* | 1778 | /* |
1709 | * If the user didn't specify a port, set the port number to | ||
1710 | * the NFS version 4 default port. | ||
1711 | */ | ||
1712 | static void nfs4_default_port(struct sockaddr *sap) | ||
1713 | { | ||
1714 | switch (sap->sa_family) { | ||
1715 | case AF_INET: { | ||
1716 | struct sockaddr_in *ap = (struct sockaddr_in *)sap; | ||
1717 | if (ap->sin_port == 0) | ||
1718 | ap->sin_port = htons(NFS_PORT); | ||
1719 | break; | ||
1720 | } | ||
1721 | case AF_INET6: { | ||
1722 | struct sockaddr_in6 *ap = (struct sockaddr_in6 *)sap; | ||
1723 | if (ap->sin6_port == 0) | ||
1724 | ap->sin6_port = htons(NFS_PORT); | ||
1725 | break; | ||
1726 | } | ||
1727 | } | ||
1728 | } | ||
1729 | |||
1730 | /* | ||
1731 | * Validate NFSv4 mount options | 1779 | * Validate NFSv4 mount options |
1732 | */ | 1780 | */ |
1733 | static int nfs4_validate_mount_data(void *options, | 1781 | static int nfs4_validate_mount_data(void *options, |
@@ -1751,6 +1799,7 @@ static int nfs4_validate_mount_data(void *options, | |||
1751 | args->acregmax = 60; | 1799 | args->acregmax = 60; |
1752 | args->acdirmin = 30; | 1800 | args->acdirmin = 30; |
1753 | args->acdirmax = 60; | 1801 | args->acdirmax = 60; |
1802 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ | ||
1754 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1803 | args->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1755 | 1804 | ||
1756 | switch (data->version) { | 1805 | switch (data->version) { |
@@ -1767,9 +1816,6 @@ static int nfs4_validate_mount_data(void *options, | |||
1767 | &args->nfs_server.address)) | 1816 | &args->nfs_server.address)) |
1768 | goto out_no_address; | 1817 | goto out_no_address; |
1769 | 1818 | ||
1770 | nfs4_default_port((struct sockaddr *) | ||
1771 | &args->nfs_server.address); | ||
1772 | |||
1773 | switch (data->auth_flavourlen) { | 1819 | switch (data->auth_flavourlen) { |
1774 | case 0: | 1820 | case 0: |
1775 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1821 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
@@ -1827,9 +1873,6 @@ static int nfs4_validate_mount_data(void *options, | |||
1827 | &args->nfs_server.address)) | 1873 | &args->nfs_server.address)) |
1828 | return -EINVAL; | 1874 | return -EINVAL; |
1829 | 1875 | ||
1830 | nfs4_default_port((struct sockaddr *) | ||
1831 | &args->nfs_server.address); | ||
1832 | |||
1833 | switch (args->auth_flavor_len) { | 1876 | switch (args->auth_flavor_len) { |
1834 | case 0: | 1877 | case 0: |
1835 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 1878 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
@@ -1852,12 +1895,16 @@ static int nfs4_validate_mount_data(void *options, | |||
1852 | return -ENAMETOOLONG; | 1895 | return -ENAMETOOLONG; |
1853 | /* N.B. caller will free nfs_server.hostname in all cases */ | 1896 | /* N.B. caller will free nfs_server.hostname in all cases */ |
1854 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); | 1897 | args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); |
1898 | if (!args->nfs_server.hostname) | ||
1899 | goto out_nomem; | ||
1855 | 1900 | ||
1856 | c++; /* step over the ':' */ | 1901 | c++; /* step over the ':' */ |
1857 | len = strlen(c); | 1902 | len = strlen(c); |
1858 | if (len > NFS4_MAXPATHLEN) | 1903 | if (len > NFS4_MAXPATHLEN) |
1859 | return -ENAMETOOLONG; | 1904 | return -ENAMETOOLONG; |
1860 | args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL); | 1905 | args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL); |
1906 | if (!args->nfs_server.export_path) | ||
1907 | goto out_nomem; | ||
1861 | 1908 | ||
1862 | dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path); | 1909 | dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path); |
1863 | 1910 | ||
@@ -1879,6 +1926,10 @@ out_inval_auth: | |||
1879 | data->auth_flavourlen); | 1926 | data->auth_flavourlen); |
1880 | return -EINVAL; | 1927 | return -EINVAL; |
1881 | 1928 | ||
1929 | out_nomem: | ||
1930 | dfprintk(MOUNT, "NFS4: not enough memory to handle mount options\n"); | ||
1931 | return -ENOMEM; | ||
1932 | |||
1882 | out_no_address: | 1933 | out_no_address: |
1883 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); | 1934 | dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); |
1884 | return -EINVAL; | 1935 | return -EINVAL; |
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 83e865a16ad1..412738dbfbc7 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c | |||
@@ -10,7 +10,6 @@ | |||
10 | * nfs symlink handling code | 10 | * nfs symlink handling code |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #define NFS_NEED_XDR_TYPES | ||
14 | #include <linux/time.h> | 13 | #include <linux/time.h> |
15 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
16 | #include <linux/sunrpc/clnt.h> | 15 | #include <linux/sunrpc/clnt.h> |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 757415363422..3adf8b266461 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -234,7 +234,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry) | |||
234 | if (data == NULL) | 234 | if (data == NULL) |
235 | goto out; | 235 | goto out; |
236 | 236 | ||
237 | data->cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | 237 | data->cred = rpc_lookup_cred(); |
238 | if (IS_ERR(data->cred)) { | 238 | if (IS_ERR(data->cred)) { |
239 | status = PTR_ERR(data->cred); | 239 | status = PTR_ERR(data->cred); |
240 | goto out_free; | 240 | goto out_free; |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index bed63416a55b..1ade11d1ba07 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -48,7 +48,7 @@ static struct kmem_cache *nfs_wdata_cachep; | |||
48 | static mempool_t *nfs_wdata_mempool; | 48 | static mempool_t *nfs_wdata_mempool; |
49 | static mempool_t *nfs_commit_mempool; | 49 | static mempool_t *nfs_commit_mempool; |
50 | 50 | ||
51 | struct nfs_write_data *nfs_commit_alloc(void) | 51 | struct nfs_write_data *nfs_commitdata_alloc(void) |
52 | { | 52 | { |
53 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); | 53 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); |
54 | 54 | ||
@@ -59,19 +59,13 @@ struct nfs_write_data *nfs_commit_alloc(void) | |||
59 | return p; | 59 | return p; |
60 | } | 60 | } |
61 | 61 | ||
62 | static void nfs_commit_rcu_free(struct rcu_head *head) | 62 | void nfs_commit_free(struct nfs_write_data *p) |
63 | { | 63 | { |
64 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); | ||
65 | if (p && (p->pagevec != &p->page_array[0])) | 64 | if (p && (p->pagevec != &p->page_array[0])) |
66 | kfree(p->pagevec); | 65 | kfree(p->pagevec); |
67 | mempool_free(p, nfs_commit_mempool); | 66 | mempool_free(p, nfs_commit_mempool); |
68 | } | 67 | } |
69 | 68 | ||
70 | void nfs_commit_free(struct nfs_write_data *wdata) | ||
71 | { | ||
72 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free); | ||
73 | } | ||
74 | |||
75 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | 69 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) |
76 | { | 70 | { |
77 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); | 71 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); |
@@ -93,21 +87,18 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | |||
93 | return p; | 87 | return p; |
94 | } | 88 | } |
95 | 89 | ||
96 | static void nfs_writedata_rcu_free(struct rcu_head *head) | 90 | static void nfs_writedata_free(struct nfs_write_data *p) |
97 | { | 91 | { |
98 | struct nfs_write_data *p = container_of(head, struct nfs_write_data, task.u.tk_rcu); | ||
99 | if (p && (p->pagevec != &p->page_array[0])) | 92 | if (p && (p->pagevec != &p->page_array[0])) |
100 | kfree(p->pagevec); | 93 | kfree(p->pagevec); |
101 | mempool_free(p, nfs_wdata_mempool); | 94 | mempool_free(p, nfs_wdata_mempool); |
102 | } | 95 | } |
103 | 96 | ||
104 | static void nfs_writedata_free(struct nfs_write_data *wdata) | 97 | void nfs_writedata_release(void *data) |
105 | { | 98 | { |
106 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_writedata_rcu_free); | 99 | struct nfs_write_data *wdata = data; |
107 | } | ||
108 | 100 | ||
109 | void nfs_writedata_release(void *wdata) | 101 | put_nfs_open_context(wdata->args.context); |
110 | { | ||
111 | nfs_writedata_free(wdata); | 102 | nfs_writedata_free(wdata); |
112 | } | 103 | } |
113 | 104 | ||
@@ -291,8 +282,6 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
291 | spin_unlock(&inode->i_lock); | 282 | spin_unlock(&inode->i_lock); |
292 | if (!nfs_pageio_add_request(pgio, req)) { | 283 | if (!nfs_pageio_add_request(pgio, req)) { |
293 | nfs_redirty_request(req); | 284 | nfs_redirty_request(req); |
294 | nfs_end_page_writeback(page); | ||
295 | nfs_clear_page_tag_locked(req); | ||
296 | return pgio->pg_error; | 285 | return pgio->pg_error; |
297 | } | 286 | } |
298 | return 0; | 287 | return 0; |
@@ -366,15 +355,13 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
366 | /* | 355 | /* |
367 | * Insert a write request into an inode | 356 | * Insert a write request into an inode |
368 | */ | 357 | */ |
369 | static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | 358 | static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req) |
370 | { | 359 | { |
371 | struct nfs_inode *nfsi = NFS_I(inode); | 360 | struct nfs_inode *nfsi = NFS_I(inode); |
372 | int error; | 361 | int error; |
373 | 362 | ||
374 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); | 363 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); |
375 | BUG_ON(error == -EEXIST); | 364 | BUG_ON(error); |
376 | if (error) | ||
377 | return error; | ||
378 | if (!nfsi->npages) { | 365 | if (!nfsi->npages) { |
379 | igrab(inode); | 366 | igrab(inode); |
380 | if (nfs_have_delegation(inode, FMODE_WRITE)) | 367 | if (nfs_have_delegation(inode, FMODE_WRITE)) |
@@ -384,8 +371,8 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
384 | set_page_private(req->wb_page, (unsigned long)req); | 371 | set_page_private(req->wb_page, (unsigned long)req); |
385 | nfsi->npages++; | 372 | nfsi->npages++; |
386 | kref_get(&req->wb_kref); | 373 | kref_get(&req->wb_kref); |
387 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 374 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, |
388 | return 0; | 375 | NFS_PAGE_TAG_LOCKED); |
389 | } | 376 | } |
390 | 377 | ||
391 | /* | 378 | /* |
@@ -413,7 +400,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
413 | } | 400 | } |
414 | 401 | ||
415 | static void | 402 | static void |
416 | nfs_redirty_request(struct nfs_page *req) | 403 | nfs_mark_request_dirty(struct nfs_page *req) |
417 | { | 404 | { |
418 | __set_page_dirty_nobuffers(req->wb_page); | 405 | __set_page_dirty_nobuffers(req->wb_page); |
419 | } | 406 | } |
@@ -467,7 +454,7 @@ int nfs_reschedule_unstable_write(struct nfs_page *req) | |||
467 | return 1; | 454 | return 1; |
468 | } | 455 | } |
469 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { | 456 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { |
470 | nfs_redirty_request(req); | 457 | nfs_mark_request_dirty(req); |
471 | return 1; | 458 | return 1; |
472 | } | 459 | } |
473 | return 0; | 460 | return 0; |
@@ -597,6 +584,13 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
597 | /* Loop over all inode entries and see if we find | 584 | /* Loop over all inode entries and see if we find |
598 | * A request for the page we wish to update | 585 | * A request for the page we wish to update |
599 | */ | 586 | */ |
587 | if (new) { | ||
588 | if (radix_tree_preload(GFP_NOFS)) { | ||
589 | nfs_release_request(new); | ||
590 | return ERR_PTR(-ENOMEM); | ||
591 | } | ||
592 | } | ||
593 | |||
600 | spin_lock(&inode->i_lock); | 594 | spin_lock(&inode->i_lock); |
601 | req = nfs_page_find_request_locked(page); | 595 | req = nfs_page_find_request_locked(page); |
602 | if (req) { | 596 | if (req) { |
@@ -607,28 +601,27 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
607 | error = nfs_wait_on_request(req); | 601 | error = nfs_wait_on_request(req); |
608 | nfs_release_request(req); | 602 | nfs_release_request(req); |
609 | if (error < 0) { | 603 | if (error < 0) { |
610 | if (new) | 604 | if (new) { |
605 | radix_tree_preload_end(); | ||
611 | nfs_release_request(new); | 606 | nfs_release_request(new); |
607 | } | ||
612 | return ERR_PTR(error); | 608 | return ERR_PTR(error); |
613 | } | 609 | } |
614 | continue; | 610 | continue; |
615 | } | 611 | } |
616 | spin_unlock(&inode->i_lock); | 612 | spin_unlock(&inode->i_lock); |
617 | if (new) | 613 | if (new) { |
614 | radix_tree_preload_end(); | ||
618 | nfs_release_request(new); | 615 | nfs_release_request(new); |
616 | } | ||
619 | break; | 617 | break; |
620 | } | 618 | } |
621 | 619 | ||
622 | if (new) { | 620 | if (new) { |
623 | int error; | ||
624 | nfs_lock_request_dontget(new); | 621 | nfs_lock_request_dontget(new); |
625 | error = nfs_inode_add_request(inode, new); | 622 | nfs_inode_add_request(inode, new); |
626 | if (error) { | ||
627 | spin_unlock(&inode->i_lock); | ||
628 | nfs_unlock_request(new); | ||
629 | return ERR_PTR(error); | ||
630 | } | ||
631 | spin_unlock(&inode->i_lock); | 623 | spin_unlock(&inode->i_lock); |
624 | radix_tree_preload_end(); | ||
632 | req = new; | 625 | req = new; |
633 | goto zero_page; | 626 | goto zero_page; |
634 | } | 627 | } |
@@ -785,7 +778,7 @@ static int flush_task_priority(int how) | |||
785 | /* | 778 | /* |
786 | * Set up the argument/result storage required for the RPC call. | 779 | * Set up the argument/result storage required for the RPC call. |
787 | */ | 780 | */ |
788 | static void nfs_write_rpcsetup(struct nfs_page *req, | 781 | static int nfs_write_rpcsetup(struct nfs_page *req, |
789 | struct nfs_write_data *data, | 782 | struct nfs_write_data *data, |
790 | const struct rpc_call_ops *call_ops, | 783 | const struct rpc_call_ops *call_ops, |
791 | unsigned int count, unsigned int offset, | 784 | unsigned int count, unsigned int offset, |
@@ -806,6 +799,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
806 | .rpc_message = &msg, | 799 | .rpc_message = &msg, |
807 | .callback_ops = call_ops, | 800 | .callback_ops = call_ops, |
808 | .callback_data = data, | 801 | .callback_data = data, |
802 | .workqueue = nfsiod_workqueue, | ||
809 | .flags = flags, | 803 | .flags = flags, |
810 | .priority = priority, | 804 | .priority = priority, |
811 | }; | 805 | }; |
@@ -822,7 +816,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
822 | data->args.pgbase = req->wb_pgbase + offset; | 816 | data->args.pgbase = req->wb_pgbase + offset; |
823 | data->args.pages = data->pagevec; | 817 | data->args.pages = data->pagevec; |
824 | data->args.count = count; | 818 | data->args.count = count; |
825 | data->args.context = req->wb_context; | 819 | data->args.context = get_nfs_open_context(req->wb_context); |
826 | data->args.stable = NFS_UNSTABLE; | 820 | data->args.stable = NFS_UNSTABLE; |
827 | if (how & FLUSH_STABLE) { | 821 | if (how & FLUSH_STABLE) { |
828 | data->args.stable = NFS_DATA_SYNC; | 822 | data->args.stable = NFS_DATA_SYNC; |
@@ -847,8 +841,21 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
847 | (unsigned long long)data->args.offset); | 841 | (unsigned long long)data->args.offset); |
848 | 842 | ||
849 | task = rpc_run_task(&task_setup_data); | 843 | task = rpc_run_task(&task_setup_data); |
850 | if (!IS_ERR(task)) | 844 | if (IS_ERR(task)) |
851 | rpc_put_task(task); | 845 | return PTR_ERR(task); |
846 | rpc_put_task(task); | ||
847 | return 0; | ||
848 | } | ||
849 | |||
850 | /* If a nfs_flush_* function fails, it should remove reqs from @head and | ||
851 | * call this on each, which will prepare them to be retried on next | ||
852 | * writeback using standard nfs. | ||
853 | */ | ||
854 | static void nfs_redirty_request(struct nfs_page *req) | ||
855 | { | ||
856 | nfs_mark_request_dirty(req); | ||
857 | nfs_end_page_writeback(req->wb_page); | ||
858 | nfs_clear_page_tag_locked(req); | ||
852 | } | 859 | } |
853 | 860 | ||
854 | /* | 861 | /* |
@@ -863,6 +870,7 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
863 | size_t wsize = NFS_SERVER(inode)->wsize, nbytes; | 870 | size_t wsize = NFS_SERVER(inode)->wsize, nbytes; |
864 | unsigned int offset; | 871 | unsigned int offset; |
865 | int requests = 0; | 872 | int requests = 0; |
873 | int ret = 0; | ||
866 | LIST_HEAD(list); | 874 | LIST_HEAD(list); |
867 | 875 | ||
868 | nfs_list_remove_request(req); | 876 | nfs_list_remove_request(req); |
@@ -884,6 +892,8 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
884 | offset = 0; | 892 | offset = 0; |
885 | nbytes = count; | 893 | nbytes = count; |
886 | do { | 894 | do { |
895 | int ret2; | ||
896 | |||
887 | data = list_entry(list.next, struct nfs_write_data, pages); | 897 | data = list_entry(list.next, struct nfs_write_data, pages); |
888 | list_del_init(&data->pages); | 898 | list_del_init(&data->pages); |
889 | 899 | ||
@@ -891,13 +901,15 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
891 | 901 | ||
892 | if (nbytes < wsize) | 902 | if (nbytes < wsize) |
893 | wsize = nbytes; | 903 | wsize = nbytes; |
894 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, | 904 | ret2 = nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, |
895 | wsize, offset, how); | 905 | wsize, offset, how); |
906 | if (ret == 0) | ||
907 | ret = ret2; | ||
896 | offset += wsize; | 908 | offset += wsize; |
897 | nbytes -= wsize; | 909 | nbytes -= wsize; |
898 | } while (nbytes != 0); | 910 | } while (nbytes != 0); |
899 | 911 | ||
900 | return 0; | 912 | return ret; |
901 | 913 | ||
902 | out_bad: | 914 | out_bad: |
903 | while (!list_empty(&list)) { | 915 | while (!list_empty(&list)) { |
@@ -906,8 +918,6 @@ out_bad: | |||
906 | nfs_writedata_release(data); | 918 | nfs_writedata_release(data); |
907 | } | 919 | } |
908 | nfs_redirty_request(req); | 920 | nfs_redirty_request(req); |
909 | nfs_end_page_writeback(req->wb_page); | ||
910 | nfs_clear_page_tag_locked(req); | ||
911 | return -ENOMEM; | 921 | return -ENOMEM; |
912 | } | 922 | } |
913 | 923 | ||
@@ -940,16 +950,12 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i | |||
940 | req = nfs_list_entry(data->pages.next); | 950 | req = nfs_list_entry(data->pages.next); |
941 | 951 | ||
942 | /* Set up the argument struct */ | 952 | /* Set up the argument struct */ |
943 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); | 953 | return nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); |
944 | |||
945 | return 0; | ||
946 | out_bad: | 954 | out_bad: |
947 | while (!list_empty(head)) { | 955 | while (!list_empty(head)) { |
948 | req = nfs_list_entry(head->next); | 956 | req = nfs_list_entry(head->next); |
949 | nfs_list_remove_request(req); | 957 | nfs_list_remove_request(req); |
950 | nfs_redirty_request(req); | 958 | nfs_redirty_request(req); |
951 | nfs_end_page_writeback(req->wb_page); | ||
952 | nfs_clear_page_tag_locked(req); | ||
953 | } | 959 | } |
954 | return -ENOMEM; | 960 | return -ENOMEM; |
955 | } | 961 | } |
@@ -972,7 +978,6 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
972 | { | 978 | { |
973 | struct nfs_write_data *data = calldata; | 979 | struct nfs_write_data *data = calldata; |
974 | struct nfs_page *req = data->req; | 980 | struct nfs_page *req = data->req; |
975 | struct page *page = req->wb_page; | ||
976 | 981 | ||
977 | dprintk("NFS: write (%s/%Ld %d@%Ld)", | 982 | dprintk("NFS: write (%s/%Ld %d@%Ld)", |
978 | req->wb_context->path.dentry->d_inode->i_sb->s_id, | 983 | req->wb_context->path.dentry->d_inode->i_sb->s_id, |
@@ -980,13 +985,20 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
980 | req->wb_bytes, | 985 | req->wb_bytes, |
981 | (long long)req_offset(req)); | 986 | (long long)req_offset(req)); |
982 | 987 | ||
983 | if (nfs_writeback_done(task, data) != 0) | 988 | nfs_writeback_done(task, data); |
984 | return; | 989 | } |
985 | 990 | ||
986 | if (task->tk_status < 0) { | 991 | static void nfs_writeback_release_partial(void *calldata) |
992 | { | ||
993 | struct nfs_write_data *data = calldata; | ||
994 | struct nfs_page *req = data->req; | ||
995 | struct page *page = req->wb_page; | ||
996 | int status = data->task.tk_status; | ||
997 | |||
998 | if (status < 0) { | ||
987 | nfs_set_pageerror(page); | 999 | nfs_set_pageerror(page); |
988 | nfs_context_set_write_error(req->wb_context, task->tk_status); | 1000 | nfs_context_set_write_error(req->wb_context, status); |
989 | dprintk(", error = %d\n", task->tk_status); | 1001 | dprintk(", error = %d\n", status); |
990 | goto out; | 1002 | goto out; |
991 | } | 1003 | } |
992 | 1004 | ||
@@ -1011,11 +1023,12 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
1011 | out: | 1023 | out: |
1012 | if (atomic_dec_and_test(&req->wb_complete)) | 1024 | if (atomic_dec_and_test(&req->wb_complete)) |
1013 | nfs_writepage_release(req); | 1025 | nfs_writepage_release(req); |
1026 | nfs_writedata_release(calldata); | ||
1014 | } | 1027 | } |
1015 | 1028 | ||
1016 | static const struct rpc_call_ops nfs_write_partial_ops = { | 1029 | static const struct rpc_call_ops nfs_write_partial_ops = { |
1017 | .rpc_call_done = nfs_writeback_done_partial, | 1030 | .rpc_call_done = nfs_writeback_done_partial, |
1018 | .rpc_release = nfs_writedata_release, | 1031 | .rpc_release = nfs_writeback_release_partial, |
1019 | }; | 1032 | }; |
1020 | 1033 | ||
1021 | /* | 1034 | /* |
@@ -1028,17 +1041,21 @@ static const struct rpc_call_ops nfs_write_partial_ops = { | |||
1028 | static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | 1041 | static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) |
1029 | { | 1042 | { |
1030 | struct nfs_write_data *data = calldata; | 1043 | struct nfs_write_data *data = calldata; |
1031 | struct nfs_page *req; | ||
1032 | struct page *page; | ||
1033 | 1044 | ||
1034 | if (nfs_writeback_done(task, data) != 0) | 1045 | nfs_writeback_done(task, data); |
1035 | return; | 1046 | } |
1047 | |||
1048 | static void nfs_writeback_release_full(void *calldata) | ||
1049 | { | ||
1050 | struct nfs_write_data *data = calldata; | ||
1051 | int status = data->task.tk_status; | ||
1036 | 1052 | ||
1037 | /* Update attributes as result of writeback. */ | 1053 | /* Update attributes as result of writeback. */ |
1038 | while (!list_empty(&data->pages)) { | 1054 | while (!list_empty(&data->pages)) { |
1039 | req = nfs_list_entry(data->pages.next); | 1055 | struct nfs_page *req = nfs_list_entry(data->pages.next); |
1056 | struct page *page = req->wb_page; | ||
1057 | |||
1040 | nfs_list_remove_request(req); | 1058 | nfs_list_remove_request(req); |
1041 | page = req->wb_page; | ||
1042 | 1059 | ||
1043 | dprintk("NFS: write (%s/%Ld %d@%Ld)", | 1060 | dprintk("NFS: write (%s/%Ld %d@%Ld)", |
1044 | req->wb_context->path.dentry->d_inode->i_sb->s_id, | 1061 | req->wb_context->path.dentry->d_inode->i_sb->s_id, |
@@ -1046,10 +1063,10 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | |||
1046 | req->wb_bytes, | 1063 | req->wb_bytes, |
1047 | (long long)req_offset(req)); | 1064 | (long long)req_offset(req)); |
1048 | 1065 | ||
1049 | if (task->tk_status < 0) { | 1066 | if (status < 0) { |
1050 | nfs_set_pageerror(page); | 1067 | nfs_set_pageerror(page); |
1051 | nfs_context_set_write_error(req->wb_context, task->tk_status); | 1068 | nfs_context_set_write_error(req->wb_context, status); |
1052 | dprintk(", error = %d\n", task->tk_status); | 1069 | dprintk(", error = %d\n", status); |
1053 | goto remove_request; | 1070 | goto remove_request; |
1054 | } | 1071 | } |
1055 | 1072 | ||
@@ -1069,11 +1086,12 @@ remove_request: | |||
1069 | next: | 1086 | next: |
1070 | nfs_clear_page_tag_locked(req); | 1087 | nfs_clear_page_tag_locked(req); |
1071 | } | 1088 | } |
1089 | nfs_writedata_release(calldata); | ||
1072 | } | 1090 | } |
1073 | 1091 | ||
1074 | static const struct rpc_call_ops nfs_write_full_ops = { | 1092 | static const struct rpc_call_ops nfs_write_full_ops = { |
1075 | .rpc_call_done = nfs_writeback_done_full, | 1093 | .rpc_call_done = nfs_writeback_done_full, |
1076 | .rpc_release = nfs_writedata_release, | 1094 | .rpc_release = nfs_writeback_release_full, |
1077 | }; | 1095 | }; |
1078 | 1096 | ||
1079 | 1097 | ||
@@ -1159,15 +1177,18 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1159 | 1177 | ||
1160 | 1178 | ||
1161 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1179 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1162 | void nfs_commit_release(void *wdata) | 1180 | void nfs_commitdata_release(void *data) |
1163 | { | 1181 | { |
1182 | struct nfs_write_data *wdata = data; | ||
1183 | |||
1184 | put_nfs_open_context(wdata->args.context); | ||
1164 | nfs_commit_free(wdata); | 1185 | nfs_commit_free(wdata); |
1165 | } | 1186 | } |
1166 | 1187 | ||
1167 | /* | 1188 | /* |
1168 | * Set up the argument/result storage required for the RPC call. | 1189 | * Set up the argument/result storage required for the RPC call. |
1169 | */ | 1190 | */ |
1170 | static void nfs_commit_rpcsetup(struct list_head *head, | 1191 | static int nfs_commit_rpcsetup(struct list_head *head, |
1171 | struct nfs_write_data *data, | 1192 | struct nfs_write_data *data, |
1172 | int how) | 1193 | int how) |
1173 | { | 1194 | { |
@@ -1187,6 +1208,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1187 | .rpc_message = &msg, | 1208 | .rpc_message = &msg, |
1188 | .callback_ops = &nfs_commit_ops, | 1209 | .callback_ops = &nfs_commit_ops, |
1189 | .callback_data = data, | 1210 | .callback_data = data, |
1211 | .workqueue = nfsiod_workqueue, | ||
1190 | .flags = flags, | 1212 | .flags = flags, |
1191 | .priority = priority, | 1213 | .priority = priority, |
1192 | }; | 1214 | }; |
@@ -1203,6 +1225,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1203 | /* Note: we always request a commit of the entire inode */ | 1225 | /* Note: we always request a commit of the entire inode */ |
1204 | data->args.offset = 0; | 1226 | data->args.offset = 0; |
1205 | data->args.count = 0; | 1227 | data->args.count = 0; |
1228 | data->args.context = get_nfs_open_context(first->wb_context); | ||
1206 | data->res.count = 0; | 1229 | data->res.count = 0; |
1207 | data->res.fattr = &data->fattr; | 1230 | data->res.fattr = &data->fattr; |
1208 | data->res.verf = &data->verf; | 1231 | data->res.verf = &data->verf; |
@@ -1214,8 +1237,10 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1214 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 1237 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
1215 | 1238 | ||
1216 | task = rpc_run_task(&task_setup_data); | 1239 | task = rpc_run_task(&task_setup_data); |
1217 | if (!IS_ERR(task)) | 1240 | if (IS_ERR(task)) |
1218 | rpc_put_task(task); | 1241 | return PTR_ERR(task); |
1242 | rpc_put_task(task); | ||
1243 | return 0; | ||
1219 | } | 1244 | } |
1220 | 1245 | ||
1221 | /* | 1246 | /* |
@@ -1227,15 +1252,13 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1227 | struct nfs_write_data *data; | 1252 | struct nfs_write_data *data; |
1228 | struct nfs_page *req; | 1253 | struct nfs_page *req; |
1229 | 1254 | ||
1230 | data = nfs_commit_alloc(); | 1255 | data = nfs_commitdata_alloc(); |
1231 | 1256 | ||
1232 | if (!data) | 1257 | if (!data) |
1233 | goto out_bad; | 1258 | goto out_bad; |
1234 | 1259 | ||
1235 | /* Set up the argument struct */ | 1260 | /* Set up the argument struct */ |
1236 | nfs_commit_rpcsetup(head, data, how); | 1261 | return nfs_commit_rpcsetup(head, data, how); |
1237 | |||
1238 | return 0; | ||
1239 | out_bad: | 1262 | out_bad: |
1240 | while (!list_empty(head)) { | 1263 | while (!list_empty(head)) { |
1241 | req = nfs_list_entry(head->next); | 1264 | req = nfs_list_entry(head->next); |
@@ -1255,7 +1278,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1255 | static void nfs_commit_done(struct rpc_task *task, void *calldata) | 1278 | static void nfs_commit_done(struct rpc_task *task, void *calldata) |
1256 | { | 1279 | { |
1257 | struct nfs_write_data *data = calldata; | 1280 | struct nfs_write_data *data = calldata; |
1258 | struct nfs_page *req; | ||
1259 | 1281 | ||
1260 | dprintk("NFS: %5u nfs_commit_done (status %d)\n", | 1282 | dprintk("NFS: %5u nfs_commit_done (status %d)\n", |
1261 | task->tk_pid, task->tk_status); | 1283 | task->tk_pid, task->tk_status); |
@@ -1263,6 +1285,13 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1263 | /* Call the NFS version-specific code */ | 1285 | /* Call the NFS version-specific code */ |
1264 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | 1286 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) |
1265 | return; | 1287 | return; |
1288 | } | ||
1289 | |||
1290 | static void nfs_commit_release(void *calldata) | ||
1291 | { | ||
1292 | struct nfs_write_data *data = calldata; | ||
1293 | struct nfs_page *req; | ||
1294 | int status = data->task.tk_status; | ||
1266 | 1295 | ||
1267 | while (!list_empty(&data->pages)) { | 1296 | while (!list_empty(&data->pages)) { |
1268 | req = nfs_list_entry(data->pages.next); | 1297 | req = nfs_list_entry(data->pages.next); |
@@ -1277,10 +1306,10 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1277 | (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), | 1306 | (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), |
1278 | req->wb_bytes, | 1307 | req->wb_bytes, |
1279 | (long long)req_offset(req)); | 1308 | (long long)req_offset(req)); |
1280 | if (task->tk_status < 0) { | 1309 | if (status < 0) { |
1281 | nfs_context_set_write_error(req->wb_context, task->tk_status); | 1310 | nfs_context_set_write_error(req->wb_context, status); |
1282 | nfs_inode_remove_request(req); | 1311 | nfs_inode_remove_request(req); |
1283 | dprintk(", error = %d\n", task->tk_status); | 1312 | dprintk(", error = %d\n", status); |
1284 | goto next; | 1313 | goto next; |
1285 | } | 1314 | } |
1286 | 1315 | ||
@@ -1297,10 +1326,11 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1297 | } | 1326 | } |
1298 | /* We have a mismatch. Write the page again */ | 1327 | /* We have a mismatch. Write the page again */ |
1299 | dprintk(" mismatch\n"); | 1328 | dprintk(" mismatch\n"); |
1300 | nfs_redirty_request(req); | 1329 | nfs_mark_request_dirty(req); |
1301 | next: | 1330 | next: |
1302 | nfs_clear_page_tag_locked(req); | 1331 | nfs_clear_page_tag_locked(req); |
1303 | } | 1332 | } |
1333 | nfs_commitdata_release(calldata); | ||
1304 | } | 1334 | } |
1305 | 1335 | ||
1306 | static const struct rpc_call_ops nfs_commit_ops = { | 1336 | static const struct rpc_call_ops nfs_commit_ops = { |
@@ -1487,18 +1517,19 @@ static int nfs_wb_page_priority(struct inode *inode, struct page *page, | |||
1487 | }; | 1517 | }; |
1488 | int ret; | 1518 | int ret; |
1489 | 1519 | ||
1490 | BUG_ON(!PageLocked(page)); | 1520 | do { |
1491 | if (clear_page_dirty_for_io(page)) { | 1521 | if (clear_page_dirty_for_io(page)) { |
1492 | ret = nfs_writepage_locked(page, &wbc); | 1522 | ret = nfs_writepage_locked(page, &wbc); |
1523 | if (ret < 0) | ||
1524 | goto out_error; | ||
1525 | } else if (!PagePrivate(page)) | ||
1526 | break; | ||
1527 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | ||
1493 | if (ret < 0) | 1528 | if (ret < 0) |
1494 | goto out; | 1529 | goto out_error; |
1495 | } | 1530 | } while (PagePrivate(page)); |
1496 | if (!PagePrivate(page)) | 1531 | return 0; |
1497 | return 0; | 1532 | out_error: |
1498 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | ||
1499 | if (ret >= 0) | ||
1500 | return 0; | ||
1501 | out: | ||
1502 | __mark_inode_dirty(inode, I_DIRTY_PAGES); | 1533 | __mark_inode_dirty(inode, I_DIRTY_PAGES); |
1503 | return ret; | 1534 | return ret; |
1504 | } | 1535 | } |
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index d13403e33622..294992e9bf69 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/sunrpc/svcauth.h> | 10 | #include <linux/sunrpc/svcauth.h> |
11 | #include <linux/nfsd/nfsd.h> | 11 | #include <linux/nfsd/nfsd.h> |
12 | #include <linux/nfsd/export.h> | 12 | #include <linux/nfsd/export.h> |
13 | #include "auth.h" | ||
13 | 14 | ||
14 | int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) | 15 | int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) |
15 | { | 16 | { |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 8a6f7c924c75..33bfcf09db46 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/lockd/bind.h> | 35 | #include <linux/lockd/bind.h> |
36 | #include <linux/sunrpc/msg_prot.h> | 36 | #include <linux/sunrpc/msg_prot.h> |
37 | #include <linux/sunrpc/gss_api.h> | 37 | #include <linux/sunrpc/gss_api.h> |
38 | #include <net/ipv6.h> | ||
38 | 39 | ||
39 | #define NFSDDBG_FACILITY NFSDDBG_EXPORT | 40 | #define NFSDDBG_FACILITY NFSDDBG_EXPORT |
40 | 41 | ||
@@ -1548,6 +1549,7 @@ exp_addclient(struct nfsctl_client *ncp) | |||
1548 | { | 1549 | { |
1549 | struct auth_domain *dom; | 1550 | struct auth_domain *dom; |
1550 | int i, err; | 1551 | int i, err; |
1552 | struct in6_addr addr6; | ||
1551 | 1553 | ||
1552 | /* First, consistency check. */ | 1554 | /* First, consistency check. */ |
1553 | err = -EINVAL; | 1555 | err = -EINVAL; |
@@ -1566,9 +1568,10 @@ exp_addclient(struct nfsctl_client *ncp) | |||
1566 | goto out_unlock; | 1568 | goto out_unlock; |
1567 | 1569 | ||
1568 | /* Insert client into hashtable. */ | 1570 | /* Insert client into hashtable. */ |
1569 | for (i = 0; i < ncp->cl_naddr; i++) | 1571 | for (i = 0; i < ncp->cl_naddr; i++) { |
1570 | auth_unix_add_addr(ncp->cl_addrlist[i], dom); | 1572 | ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6); |
1571 | 1573 | auth_unix_add_addr(&addr6, dom); | |
1574 | } | ||
1572 | auth_unix_forget_old(dom); | 1575 | auth_unix_forget_old(dom); |
1573 | auth_domain_put(dom); | 1576 | auth_domain_put(dom); |
1574 | 1577 | ||
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index aae2b29ae2c9..562abf3380d0 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -344,6 +344,21 @@ static struct rpc_version * nfs_cb_version[] = { | |||
344 | &nfs_cb_version4, | 344 | &nfs_cb_version4, |
345 | }; | 345 | }; |
346 | 346 | ||
347 | static struct rpc_program cb_program; | ||
348 | |||
349 | static struct rpc_stat cb_stats = { | ||
350 | .program = &cb_program | ||
351 | }; | ||
352 | |||
353 | #define NFS4_CALLBACK 0x40000000 | ||
354 | static struct rpc_program cb_program = { | ||
355 | .name = "nfs4_cb", | ||
356 | .number = NFS4_CALLBACK, | ||
357 | .nrvers = ARRAY_SIZE(nfs_cb_version), | ||
358 | .version = nfs_cb_version, | ||
359 | .stats = &cb_stats, | ||
360 | }; | ||
361 | |||
347 | /* Reference counting, callback cleanup, etc., all look racy as heck. | 362 | /* Reference counting, callback cleanup, etc., all look racy as heck. |
348 | * And why is cb_set an atomic? */ | 363 | * And why is cb_set an atomic? */ |
349 | 364 | ||
@@ -358,13 +373,12 @@ static int do_probe_callback(void *data) | |||
358 | .to_maxval = (NFSD_LEASE_TIME/2) * HZ, | 373 | .to_maxval = (NFSD_LEASE_TIME/2) * HZ, |
359 | .to_exponential = 1, | 374 | .to_exponential = 1, |
360 | }; | 375 | }; |
361 | struct rpc_program * program = &cb->cb_program; | ||
362 | struct rpc_create_args args = { | 376 | struct rpc_create_args args = { |
363 | .protocol = IPPROTO_TCP, | 377 | .protocol = IPPROTO_TCP, |
364 | .address = (struct sockaddr *)&addr, | 378 | .address = (struct sockaddr *)&addr, |
365 | .addrsize = sizeof(addr), | 379 | .addrsize = sizeof(addr), |
366 | .timeout = &timeparms, | 380 | .timeout = &timeparms, |
367 | .program = program, | 381 | .program = &cb_program, |
368 | .version = nfs_cb_version[1]->number, | 382 | .version = nfs_cb_version[1]->number, |
369 | .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ | 383 | .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ |
370 | .flags = (RPC_CLNT_CREATE_NOPING), | 384 | .flags = (RPC_CLNT_CREATE_NOPING), |
@@ -382,16 +396,8 @@ static int do_probe_callback(void *data) | |||
382 | addr.sin_port = htons(cb->cb_port); | 396 | addr.sin_port = htons(cb->cb_port); |
383 | addr.sin_addr.s_addr = htonl(cb->cb_addr); | 397 | addr.sin_addr.s_addr = htonl(cb->cb_addr); |
384 | 398 | ||
385 | /* Initialize rpc_program */ | ||
386 | program->name = "nfs4_cb"; | ||
387 | program->number = cb->cb_prog; | ||
388 | program->nrvers = ARRAY_SIZE(nfs_cb_version); | ||
389 | program->version = nfs_cb_version; | ||
390 | program->stats = &cb->cb_stat; | ||
391 | |||
392 | /* Initialize rpc_stat */ | 399 | /* Initialize rpc_stat */ |
393 | memset(program->stats, 0, sizeof(cb->cb_stat)); | 400 | memset(args.program->stats, 0, sizeof(struct rpc_stat)); |
394 | program->stats->program = program; | ||
395 | 401 | ||
396 | /* Create RPC client */ | 402 | /* Create RPC client */ |
397 | client = rpc_create(&args); | 403 | client = rpc_create(&args); |
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 996bd88b75ba..5b398421b051 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c | |||
@@ -202,7 +202,7 @@ static struct cache_detail idtoname_cache = { | |||
202 | .alloc = ent_alloc, | 202 | .alloc = ent_alloc, |
203 | }; | 203 | }; |
204 | 204 | ||
205 | int | 205 | static int |
206 | idtoname_parse(struct cache_detail *cd, char *buf, int buflen) | 206 | idtoname_parse(struct cache_detail *cd, char *buf, int buflen) |
207 | { | 207 | { |
208 | struct ent ent, *res; | 208 | struct ent ent, *res; |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 81a75f3081f4..8799b8708188 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -1639,6 +1639,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
1639 | locks_init_lock(&fl); | 1639 | locks_init_lock(&fl); |
1640 | fl.fl_lmops = &nfsd_lease_mng_ops; | 1640 | fl.fl_lmops = &nfsd_lease_mng_ops; |
1641 | fl.fl_flags = FL_LEASE; | 1641 | fl.fl_flags = FL_LEASE; |
1642 | fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; | ||
1642 | fl.fl_end = OFFSET_MAX; | 1643 | fl.fl_end = OFFSET_MAX; |
1643 | fl.fl_owner = (fl_owner_t)dp; | 1644 | fl.fl_owner = (fl_owner_t)dp; |
1644 | fl.fl_file = stp->st_vfs_file; | 1645 | fl.fl_file = stp->st_vfs_file; |
@@ -1647,8 +1648,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
1647 | /* vfs_setlease checks to see if delegation should be handed out. | 1648 | /* vfs_setlease checks to see if delegation should be handed out. |
1648 | * the lock_manager callbacks fl_mylease and fl_change are used | 1649 | * the lock_manager callbacks fl_mylease and fl_change are used |
1649 | */ | 1650 | */ |
1650 | if ((status = vfs_setlease(stp->st_vfs_file, | 1651 | if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) { |
1651 | flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) { | ||
1652 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); | 1652 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); |
1653 | unhash_delegation(dp); | 1653 | unhash_delegation(dp); |
1654 | flag = NFS4_OPEN_DELEGATE_NONE; | 1654 | flag = NFS4_OPEN_DELEGATE_NONE; |
@@ -1763,10 +1763,6 @@ out: | |||
1763 | return status; | 1763 | return status; |
1764 | } | 1764 | } |
1765 | 1765 | ||
1766 | static struct workqueue_struct *laundry_wq; | ||
1767 | static void laundromat_main(struct work_struct *); | ||
1768 | static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main); | ||
1769 | |||
1770 | __be32 | 1766 | __be32 |
1771 | nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1767 | nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
1772 | clientid_t *clid) | 1768 | clientid_t *clid) |
@@ -1874,7 +1870,11 @@ nfs4_laundromat(void) | |||
1874 | return clientid_val; | 1870 | return clientid_val; |
1875 | } | 1871 | } |
1876 | 1872 | ||
1877 | void | 1873 | static struct workqueue_struct *laundry_wq; |
1874 | static void laundromat_main(struct work_struct *); | ||
1875 | static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main); | ||
1876 | |||
1877 | static void | ||
1878 | laundromat_main(struct work_struct *not_used) | 1878 | laundromat_main(struct work_struct *not_used) |
1879 | { | 1879 | { |
1880 | time_t t; | 1880 | time_t t; |
@@ -1975,6 +1975,26 @@ io_during_grace_disallowed(struct inode *inode, int flags) | |||
1975 | && mandatory_lock(inode); | 1975 | && mandatory_lock(inode); |
1976 | } | 1976 | } |
1977 | 1977 | ||
1978 | static int check_stateid_generation(stateid_t *in, stateid_t *ref) | ||
1979 | { | ||
1980 | /* If the client sends us a stateid from the future, it's buggy: */ | ||
1981 | if (in->si_generation > ref->si_generation) | ||
1982 | return nfserr_bad_stateid; | ||
1983 | /* | ||
1984 | * The following, however, can happen. For example, if the | ||
1985 | * client sends an open and some IO at the same time, the open | ||
1986 | * may bump si_generation while the IO is still in flight. | ||
1987 | * Thanks to hard links and renames, the client never knows what | ||
1988 | * file an open will affect. So it could avoid that situation | ||
1989 | * only by serializing all opens and IO from the same open | ||
1990 | * owner. To recover from the old_stateid error, the client | ||
1991 | * will just have to retry the IO: | ||
1992 | */ | ||
1993 | if (in->si_generation < ref->si_generation) | ||
1994 | return nfserr_old_stateid; | ||
1995 | return nfs_ok; | ||
1996 | } | ||
1997 | |||
1978 | /* | 1998 | /* |
1979 | * Checks for stateid operations | 1999 | * Checks for stateid operations |
1980 | */ | 2000 | */ |
@@ -2023,12 +2043,8 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl | |||
2023 | goto out; | 2043 | goto out; |
2024 | stidp = &stp->st_stateid; | 2044 | stidp = &stp->st_stateid; |
2025 | } | 2045 | } |
2026 | if (stateid->si_generation > stidp->si_generation) | 2046 | status = check_stateid_generation(stateid, stidp); |
2027 | goto out; | 2047 | if (status) |
2028 | |||
2029 | /* OLD STATEID */ | ||
2030 | status = nfserr_old_stateid; | ||
2031 | if (stateid->si_generation < stidp->si_generation) | ||
2032 | goto out; | 2048 | goto out; |
2033 | if (stp) { | 2049 | if (stp) { |
2034 | if ((status = nfs4_check_openmode(stp,flags))) | 2050 | if ((status = nfs4_check_openmode(stp,flags))) |
@@ -2036,7 +2052,7 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl | |||
2036 | renew_client(stp->st_stateowner->so_client); | 2052 | renew_client(stp->st_stateowner->so_client); |
2037 | if (filpp) | 2053 | if (filpp) |
2038 | *filpp = stp->st_vfs_file; | 2054 | *filpp = stp->st_vfs_file; |
2039 | } else if (dp) { | 2055 | } else { |
2040 | if ((status = nfs4_check_delegmode(dp, flags))) | 2056 | if ((status = nfs4_check_delegmode(dp, flags))) |
2041 | goto out; | 2057 | goto out; |
2042 | renew_client(dp->dl_client); | 2058 | renew_client(dp->dl_client); |
@@ -2065,6 +2081,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
2065 | { | 2081 | { |
2066 | struct nfs4_stateid *stp; | 2082 | struct nfs4_stateid *stp; |
2067 | struct nfs4_stateowner *sop; | 2083 | struct nfs4_stateowner *sop; |
2084 | __be32 status; | ||
2068 | 2085 | ||
2069 | dprintk("NFSD: preprocess_seqid_op: seqid=%d " | 2086 | dprintk("NFSD: preprocess_seqid_op: seqid=%d " |
2070 | "stateid = (%08x/%08x/%08x/%08x)\n", seqid, | 2087 | "stateid = (%08x/%08x/%08x/%08x)\n", seqid, |
@@ -2127,7 +2144,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
2127 | } | 2144 | } |
2128 | } | 2145 | } |
2129 | 2146 | ||
2130 | if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) { | 2147 | if (nfs4_check_fh(current_fh, stp)) { |
2131 | dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n"); | 2148 | dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n"); |
2132 | return nfserr_bad_stateid; | 2149 | return nfserr_bad_stateid; |
2133 | } | 2150 | } |
@@ -2150,15 +2167,9 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
2150 | " confirmed yet!\n"); | 2167 | " confirmed yet!\n"); |
2151 | return nfserr_bad_stateid; | 2168 | return nfserr_bad_stateid; |
2152 | } | 2169 | } |
2153 | if (stateid->si_generation > stp->st_stateid.si_generation) { | 2170 | status = check_stateid_generation(stateid, &stp->st_stateid); |
2154 | dprintk("NFSD: preprocess_seqid_op: future stateid?!\n"); | 2171 | if (status) |
2155 | return nfserr_bad_stateid; | 2172 | return status; |
2156 | } | ||
2157 | |||
2158 | if (stateid->si_generation < stp->st_stateid.si_generation) { | ||
2159 | dprintk("NFSD: preprocess_seqid_op: old stateid!\n"); | ||
2160 | return nfserr_old_stateid; | ||
2161 | } | ||
2162 | renew_client(sop->so_client); | 2173 | renew_client(sop->so_client); |
2163 | return nfs_ok; | 2174 | return nfs_ok; |
2164 | 2175 | ||
@@ -2194,7 +2205,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2194 | 2205 | ||
2195 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 2206 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, |
2196 | oc->oc_seqid, &oc->oc_req_stateid, | 2207 | oc->oc_seqid, &oc->oc_req_stateid, |
2197 | CHECK_FH | CONFIRM | OPEN_STATE, | 2208 | CONFIRM | OPEN_STATE, |
2198 | &oc->oc_stateowner, &stp, NULL))) | 2209 | &oc->oc_stateowner, &stp, NULL))) |
2199 | goto out; | 2210 | goto out; |
2200 | 2211 | ||
@@ -2265,7 +2276,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
2265 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 2276 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, |
2266 | od->od_seqid, | 2277 | od->od_seqid, |
2267 | &od->od_stateid, | 2278 | &od->od_stateid, |
2268 | CHECK_FH | OPEN_STATE, | 2279 | OPEN_STATE, |
2269 | &od->od_stateowner, &stp, NULL))) | 2280 | &od->od_stateowner, &stp, NULL))) |
2270 | goto out; | 2281 | goto out; |
2271 | 2282 | ||
@@ -2318,7 +2329,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2318 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 2329 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, |
2319 | close->cl_seqid, | 2330 | close->cl_seqid, |
2320 | &close->cl_stateid, | 2331 | &close->cl_stateid, |
2321 | CHECK_FH | OPEN_STATE | CLOSE_STATE, | 2332 | OPEN_STATE | CLOSE_STATE, |
2322 | &close->cl_stateowner, &stp, NULL))) | 2333 | &close->cl_stateowner, &stp, NULL))) |
2323 | goto out; | 2334 | goto out; |
2324 | status = nfs_ok; | 2335 | status = nfs_ok; |
@@ -2623,7 +2634,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2623 | status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 2634 | status = nfs4_preprocess_seqid_op(&cstate->current_fh, |
2624 | lock->lk_new_open_seqid, | 2635 | lock->lk_new_open_seqid, |
2625 | &lock->lk_new_open_stateid, | 2636 | &lock->lk_new_open_stateid, |
2626 | CHECK_FH | OPEN_STATE, | 2637 | OPEN_STATE, |
2627 | &lock->lk_replay_owner, &open_stp, | 2638 | &lock->lk_replay_owner, &open_stp, |
2628 | lock); | 2639 | lock); |
2629 | if (status) | 2640 | if (status) |
@@ -2650,7 +2661,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2650 | status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 2661 | status = nfs4_preprocess_seqid_op(&cstate->current_fh, |
2651 | lock->lk_old_lock_seqid, | 2662 | lock->lk_old_lock_seqid, |
2652 | &lock->lk_old_lock_stateid, | 2663 | &lock->lk_old_lock_stateid, |
2653 | CHECK_FH | LOCK_STATE, | 2664 | LOCK_STATE, |
2654 | &lock->lk_replay_owner, &lock_stp, lock); | 2665 | &lock->lk_replay_owner, &lock_stp, lock); |
2655 | if (status) | 2666 | if (status) |
2656 | goto out; | 2667 | goto out; |
@@ -2701,9 +2712,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2701 | * Note: locks.c uses the BKL to protect the inode's lock list. | 2712 | * Note: locks.c uses the BKL to protect the inode's lock list. |
2702 | */ | 2713 | */ |
2703 | 2714 | ||
2704 | /* XXX?: Just to divert the locks_release_private at the start of | ||
2705 | * locks_copy_lock: */ | ||
2706 | locks_init_lock(&conflock); | ||
2707 | err = vfs_lock_file(filp, cmd, &file_lock, &conflock); | 2715 | err = vfs_lock_file(filp, cmd, &file_lock, &conflock); |
2708 | switch (-err) { | 2716 | switch (-err) { |
2709 | case 0: /* success! */ | 2717 | case 0: /* success! */ |
@@ -2847,7 +2855,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2847 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 2855 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, |
2848 | locku->lu_seqid, | 2856 | locku->lu_seqid, |
2849 | &locku->lu_stateid, | 2857 | &locku->lu_stateid, |
2850 | CHECK_FH | LOCK_STATE, | 2858 | LOCK_STATE, |
2851 | &locku->lu_stateowner, &stp, NULL))) | 2859 | &locku->lu_stateowner, &stp, NULL))) |
2852 | goto out; | 2860 | goto out; |
2853 | 2861 | ||
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 0e6a179eccaf..c513bbdf2d36 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -376,20 +376,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia | |||
376 | goto xdr_error; | 376 | goto xdr_error; |
377 | } | 377 | } |
378 | } | 378 | } |
379 | if (bmval[1] & FATTR4_WORD1_TIME_METADATA) { | ||
380 | /* We require the high 32 bits of 'seconds' to be 0, and we ignore | ||
381 | all 32 bits of 'nseconds'. */ | ||
382 | READ_BUF(12); | ||
383 | len += 12; | ||
384 | READ32(dummy32); | ||
385 | if (dummy32) | ||
386 | return nfserr_inval; | ||
387 | READ32(iattr->ia_ctime.tv_sec); | ||
388 | READ32(iattr->ia_ctime.tv_nsec); | ||
389 | if (iattr->ia_ctime.tv_nsec >= (u32)1000000000) | ||
390 | return nfserr_inval; | ||
391 | iattr->ia_valid |= ATTR_CTIME; | ||
392 | } | ||
393 | if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) { | 379 | if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) { |
394 | READ_BUF(4); | 380 | READ_BUF(4); |
395 | len += 4; | 381 | len += 4; |
@@ -1867,6 +1853,15 @@ out_serverfault: | |||
1867 | goto out; | 1853 | goto out; |
1868 | } | 1854 | } |
1869 | 1855 | ||
1856 | static inline int attributes_need_mount(u32 *bmval) | ||
1857 | { | ||
1858 | if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME)) | ||
1859 | return 1; | ||
1860 | if (bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) | ||
1861 | return 1; | ||
1862 | return 0; | ||
1863 | } | ||
1864 | |||
1870 | static __be32 | 1865 | static __be32 |
1871 | nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, | 1866 | nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, |
1872 | const char *name, int namlen, __be32 *p, int *buflen) | 1867 | const char *name, int namlen, __be32 *p, int *buflen) |
@@ -1888,9 +1883,7 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, | |||
1888 | * we will not follow the cross mount and will fill the attribtutes | 1883 | * we will not follow the cross mount and will fill the attribtutes |
1889 | * directly from the mountpoint dentry. | 1884 | * directly from the mountpoint dentry. |
1890 | */ | 1885 | */ |
1891 | if (d_mountpoint(dentry) && | 1886 | if (d_mountpoint(dentry) && !attributes_need_mount(cd->rd_bmval)) |
1892 | (cd->rd_bmval[0] & ~FATTR4_WORD0_RDATTR_ERROR) == 0 && | ||
1893 | (cd->rd_bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) == 0) | ||
1894 | ignore_crossmnt = 1; | 1887 | ignore_crossmnt = 1; |
1895 | else if (d_mountpoint(dentry)) { | 1888 | else if (d_mountpoint(dentry)) { |
1896 | int err; | 1889 | int err; |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 8516137cdbb0..42f3820ee8f5 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
23 | #include <linux/pagemap.h> | 23 | #include <linux/pagemap.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/inet.h> | ||
25 | #include <linux/string.h> | 26 | #include <linux/string.h> |
26 | #include <linux/smp_lock.h> | 27 | #include <linux/smp_lock.h> |
27 | #include <linux/ctype.h> | 28 | #include <linux/ctype.h> |
@@ -35,8 +36,10 @@ | |||
35 | #include <linux/nfsd/cache.h> | 36 | #include <linux/nfsd/cache.h> |
36 | #include <linux/nfsd/xdr.h> | 37 | #include <linux/nfsd/xdr.h> |
37 | #include <linux/nfsd/syscall.h> | 38 | #include <linux/nfsd/syscall.h> |
39 | #include <linux/lockd/lockd.h> | ||
38 | 40 | ||
39 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
42 | #include <net/ipv6.h> | ||
40 | 43 | ||
41 | /* | 44 | /* |
42 | * We have a single directory with 9 nodes in it. | 45 | * We have a single directory with 9 nodes in it. |
@@ -52,6 +55,8 @@ enum { | |||
52 | NFSD_Getfs, | 55 | NFSD_Getfs, |
53 | NFSD_List, | 56 | NFSD_List, |
54 | NFSD_Fh, | 57 | NFSD_Fh, |
58 | NFSD_FO_UnlockIP, | ||
59 | NFSD_FO_UnlockFS, | ||
55 | NFSD_Threads, | 60 | NFSD_Threads, |
56 | NFSD_Pool_Threads, | 61 | NFSD_Pool_Threads, |
57 | NFSD_Versions, | 62 | NFSD_Versions, |
@@ -88,6 +93,9 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size); | |||
88 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); | 93 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); |
89 | #endif | 94 | #endif |
90 | 95 | ||
96 | static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size); | ||
97 | static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size); | ||
98 | |||
91 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { | 99 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { |
92 | [NFSD_Svc] = write_svc, | 100 | [NFSD_Svc] = write_svc, |
93 | [NFSD_Add] = write_add, | 101 | [NFSD_Add] = write_add, |
@@ -97,6 +105,8 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = { | |||
97 | [NFSD_Getfd] = write_getfd, | 105 | [NFSD_Getfd] = write_getfd, |
98 | [NFSD_Getfs] = write_getfs, | 106 | [NFSD_Getfs] = write_getfs, |
99 | [NFSD_Fh] = write_filehandle, | 107 | [NFSD_Fh] = write_filehandle, |
108 | [NFSD_FO_UnlockIP] = failover_unlock_ip, | ||
109 | [NFSD_FO_UnlockFS] = failover_unlock_fs, | ||
100 | [NFSD_Threads] = write_threads, | 110 | [NFSD_Threads] = write_threads, |
101 | [NFSD_Pool_Threads] = write_pool_threads, | 111 | [NFSD_Pool_Threads] = write_pool_threads, |
102 | [NFSD_Versions] = write_versions, | 112 | [NFSD_Versions] = write_versions, |
@@ -149,7 +159,6 @@ static const struct file_operations transaction_ops = { | |||
149 | .release = simple_transaction_release, | 159 | .release = simple_transaction_release, |
150 | }; | 160 | }; |
151 | 161 | ||
152 | extern struct seq_operations nfs_exports_op; | ||
153 | static int exports_open(struct inode *inode, struct file *file) | 162 | static int exports_open(struct inode *inode, struct file *file) |
154 | { | 163 | { |
155 | return seq_open(file, &nfs_exports_op); | 164 | return seq_open(file, &nfs_exports_op); |
@@ -222,6 +231,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size) | |||
222 | struct auth_domain *clp; | 231 | struct auth_domain *clp; |
223 | int err = 0; | 232 | int err = 0; |
224 | struct knfsd_fh *res; | 233 | struct knfsd_fh *res; |
234 | struct in6_addr in6; | ||
225 | 235 | ||
226 | if (size < sizeof(*data)) | 236 | if (size < sizeof(*data)) |
227 | return -EINVAL; | 237 | return -EINVAL; |
@@ -236,7 +246,11 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size) | |||
236 | res = (struct knfsd_fh*)buf; | 246 | res = (struct knfsd_fh*)buf; |
237 | 247 | ||
238 | exp_readlock(); | 248 | exp_readlock(); |
239 | if (!(clp = auth_unix_lookup(sin->sin_addr))) | 249 | |
250 | ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6); | ||
251 | |||
252 | clp = auth_unix_lookup(&in6); | ||
253 | if (!clp) | ||
240 | err = -EPERM; | 254 | err = -EPERM; |
241 | else { | 255 | else { |
242 | err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen); | 256 | err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen); |
@@ -257,6 +271,7 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size) | |||
257 | int err = 0; | 271 | int err = 0; |
258 | struct knfsd_fh fh; | 272 | struct knfsd_fh fh; |
259 | char *res; | 273 | char *res; |
274 | struct in6_addr in6; | ||
260 | 275 | ||
261 | if (size < sizeof(*data)) | 276 | if (size < sizeof(*data)) |
262 | return -EINVAL; | 277 | return -EINVAL; |
@@ -271,7 +286,11 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size) | |||
271 | res = buf; | 286 | res = buf; |
272 | sin = (struct sockaddr_in *)&data->gd_addr; | 287 | sin = (struct sockaddr_in *)&data->gd_addr; |
273 | exp_readlock(); | 288 | exp_readlock(); |
274 | if (!(clp = auth_unix_lookup(sin->sin_addr))) | 289 | |
290 | ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6); | ||
291 | |||
292 | clp = auth_unix_lookup(&in6); | ||
293 | if (!clp) | ||
275 | err = -EPERM; | 294 | err = -EPERM; |
276 | else { | 295 | else { |
277 | err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE); | 296 | err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE); |
@@ -288,6 +307,58 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size) | |||
288 | return err; | 307 | return err; |
289 | } | 308 | } |
290 | 309 | ||
310 | static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size) | ||
311 | { | ||
312 | __be32 server_ip; | ||
313 | char *fo_path, c; | ||
314 | int b1, b2, b3, b4; | ||
315 | |||
316 | /* sanity check */ | ||
317 | if (size == 0) | ||
318 | return -EINVAL; | ||
319 | |||
320 | if (buf[size-1] != '\n') | ||
321 | return -EINVAL; | ||
322 | |||
323 | fo_path = buf; | ||
324 | if (qword_get(&buf, fo_path, size) < 0) | ||
325 | return -EINVAL; | ||
326 | |||
327 | /* get ipv4 address */ | ||
328 | if (sscanf(fo_path, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4) | ||
329 | return -EINVAL; | ||
330 | server_ip = htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4); | ||
331 | |||
332 | return nlmsvc_unlock_all_by_ip(server_ip); | ||
333 | } | ||
334 | |||
335 | static ssize_t failover_unlock_fs(struct file *file, char *buf, size_t size) | ||
336 | { | ||
337 | struct nameidata nd; | ||
338 | char *fo_path; | ||
339 | int error; | ||
340 | |||
341 | /* sanity check */ | ||
342 | if (size == 0) | ||
343 | return -EINVAL; | ||
344 | |||
345 | if (buf[size-1] != '\n') | ||
346 | return -EINVAL; | ||
347 | |||
348 | fo_path = buf; | ||
349 | if (qword_get(&buf, fo_path, size) < 0) | ||
350 | return -EINVAL; | ||
351 | |||
352 | error = path_lookup(fo_path, 0, &nd); | ||
353 | if (error) | ||
354 | return error; | ||
355 | |||
356 | error = nlmsvc_unlock_all_by_sb(nd.path.mnt->mnt_sb); | ||
357 | |||
358 | path_put(&nd.path); | ||
359 | return error; | ||
360 | } | ||
361 | |||
291 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size) | 362 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size) |
292 | { | 363 | { |
293 | /* request is: | 364 | /* request is: |
@@ -347,8 +418,6 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size) | |||
347 | return mesg - buf; | 418 | return mesg - buf; |
348 | } | 419 | } |
349 | 420 | ||
350 | extern int nfsd_nrthreads(void); | ||
351 | |||
352 | static ssize_t write_threads(struct file *file, char *buf, size_t size) | 421 | static ssize_t write_threads(struct file *file, char *buf, size_t size) |
353 | { | 422 | { |
354 | /* if size > 0, look for a number of threads and call nfsd_svc | 423 | /* if size > 0, look for a number of threads and call nfsd_svc |
@@ -371,10 +440,6 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) | |||
371 | return strlen(buf); | 440 | return strlen(buf); |
372 | } | 441 | } |
373 | 442 | ||
374 | extern int nfsd_nrpools(void); | ||
375 | extern int nfsd_get_nrthreads(int n, int *); | ||
376 | extern int nfsd_set_nrthreads(int n, int *); | ||
377 | |||
378 | static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) | 443 | static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) |
379 | { | 444 | { |
380 | /* if size > 0, look for an array of number of threads per node | 445 | /* if size > 0, look for an array of number of threads per node |
@@ -696,6 +761,10 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) | |||
696 | [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR}, | 761 | [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR}, |
697 | [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR}, | 762 | [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR}, |
698 | [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, | 763 | [NFSD_List] = {"exports", &exports_operations, S_IRUGO}, |
764 | [NFSD_FO_UnlockIP] = {"unlock_ip", | ||
765 | &transaction_ops, S_IWUSR|S_IRUSR}, | ||
766 | [NFSD_FO_UnlockFS] = {"unlock_filesystem", | ||
767 | &transaction_ops, S_IWUSR|S_IRUSR}, | ||
699 | [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, | 768 | [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR}, |
700 | [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, | 769 | [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, |
701 | [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR}, | 770 | [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR}, |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 3e6b3f41ee1f..100ae5641162 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -113,6 +113,124 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp, | |||
113 | } | 113 | } |
114 | 114 | ||
115 | /* | 115 | /* |
116 | * Use the given filehandle to look up the corresponding export and | ||
117 | * dentry. On success, the results are used to set fh_export and | ||
118 | * fh_dentry. | ||
119 | */ | ||
120 | static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) | ||
121 | { | ||
122 | struct knfsd_fh *fh = &fhp->fh_handle; | ||
123 | struct fid *fid = NULL, sfid; | ||
124 | struct svc_export *exp; | ||
125 | struct dentry *dentry; | ||
126 | int fileid_type; | ||
127 | int data_left = fh->fh_size/4; | ||
128 | __be32 error; | ||
129 | |||
130 | error = nfserr_stale; | ||
131 | if (rqstp->rq_vers > 2) | ||
132 | error = nfserr_badhandle; | ||
133 | if (rqstp->rq_vers == 4 && fh->fh_size == 0) | ||
134 | return nfserr_nofilehandle; | ||
135 | |||
136 | if (fh->fh_version == 1) { | ||
137 | int len; | ||
138 | |||
139 | if (--data_left < 0) | ||
140 | return error; | ||
141 | if (fh->fh_auth_type != 0) | ||
142 | return error; | ||
143 | len = key_len(fh->fh_fsid_type) / 4; | ||
144 | if (len == 0) | ||
145 | return error; | ||
146 | if (fh->fh_fsid_type == FSID_MAJOR_MINOR) { | ||
147 | /* deprecated, convert to type 3 */ | ||
148 | len = key_len(FSID_ENCODE_DEV)/4; | ||
149 | fh->fh_fsid_type = FSID_ENCODE_DEV; | ||
150 | fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1]))); | ||
151 | fh->fh_fsid[1] = fh->fh_fsid[2]; | ||
152 | } | ||
153 | data_left -= len; | ||
154 | if (data_left < 0) | ||
155 | return error; | ||
156 | exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_auth); | ||
157 | fid = (struct fid *)(fh->fh_auth + len); | ||
158 | } else { | ||
159 | __u32 tfh[2]; | ||
160 | dev_t xdev; | ||
161 | ino_t xino; | ||
162 | |||
163 | if (fh->fh_size != NFS_FHSIZE) | ||
164 | return error; | ||
165 | /* assume old filehandle format */ | ||
166 | xdev = old_decode_dev(fh->ofh_xdev); | ||
167 | xino = u32_to_ino_t(fh->ofh_xino); | ||
168 | mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); | ||
169 | exp = rqst_exp_find(rqstp, FSID_DEV, tfh); | ||
170 | } | ||
171 | |||
172 | error = nfserr_stale; | ||
173 | if (PTR_ERR(exp) == -ENOENT) | ||
174 | return error; | ||
175 | |||
176 | if (IS_ERR(exp)) | ||
177 | return nfserrno(PTR_ERR(exp)); | ||
178 | |||
179 | error = nfsd_setuser_and_check_port(rqstp, exp); | ||
180 | if (error) | ||
181 | goto out; | ||
182 | |||
183 | /* | ||
184 | * Look up the dentry using the NFS file handle. | ||
185 | */ | ||
186 | error = nfserr_stale; | ||
187 | if (rqstp->rq_vers > 2) | ||
188 | error = nfserr_badhandle; | ||
189 | |||
190 | if (fh->fh_version != 1) { | ||
191 | sfid.i32.ino = fh->ofh_ino; | ||
192 | sfid.i32.gen = fh->ofh_generation; | ||
193 | sfid.i32.parent_ino = fh->ofh_dirino; | ||
194 | fid = &sfid; | ||
195 | data_left = 3; | ||
196 | if (fh->ofh_dirino == 0) | ||
197 | fileid_type = FILEID_INO32_GEN; | ||
198 | else | ||
199 | fileid_type = FILEID_INO32_GEN_PARENT; | ||
200 | } else | ||
201 | fileid_type = fh->fh_fileid_type; | ||
202 | |||
203 | if (fileid_type == FILEID_ROOT) | ||
204 | dentry = dget(exp->ex_path.dentry); | ||
205 | else { | ||
206 | dentry = exportfs_decode_fh(exp->ex_path.mnt, fid, | ||
207 | data_left, fileid_type, | ||
208 | nfsd_acceptable, exp); | ||
209 | } | ||
210 | if (dentry == NULL) | ||
211 | goto out; | ||
212 | if (IS_ERR(dentry)) { | ||
213 | if (PTR_ERR(dentry) != -EINVAL) | ||
214 | error = nfserrno(PTR_ERR(dentry)); | ||
215 | goto out; | ||
216 | } | ||
217 | |||
218 | if (S_ISDIR(dentry->d_inode->i_mode) && | ||
219 | (dentry->d_flags & DCACHE_DISCONNECTED)) { | ||
220 | printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n", | ||
221 | dentry->d_parent->d_name.name, dentry->d_name.name); | ||
222 | } | ||
223 | |||
224 | fhp->fh_dentry = dentry; | ||
225 | fhp->fh_export = exp; | ||
226 | nfsd_nr_verified++; | ||
227 | return 0; | ||
228 | out: | ||
229 | exp_put(exp); | ||
230 | return error; | ||
231 | } | ||
232 | |||
233 | /* | ||
116 | * Perform sanity checks on the dentry in a client's file handle. | 234 | * Perform sanity checks on the dentry in a client's file handle. |
117 | * | 235 | * |
118 | * Note that the file handle dentry may need to be freed even after | 236 | * Note that the file handle dentry may need to be freed even after |
@@ -124,115 +242,18 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp, | |||
124 | __be32 | 242 | __be32 |
125 | fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | 243 | fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) |
126 | { | 244 | { |
127 | struct knfsd_fh *fh = &fhp->fh_handle; | 245 | struct svc_export *exp; |
128 | struct svc_export *exp = NULL; | ||
129 | struct dentry *dentry; | 246 | struct dentry *dentry; |
130 | __be32 error = 0; | 247 | __be32 error; |
131 | 248 | ||
132 | dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); | 249 | dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp)); |
133 | 250 | ||
134 | if (!fhp->fh_dentry) { | 251 | if (!fhp->fh_dentry) { |
135 | struct fid *fid = NULL, sfid; | 252 | error = nfsd_set_fh_dentry(rqstp, fhp); |
136 | int fileid_type; | ||
137 | int data_left = fh->fh_size/4; | ||
138 | |||
139 | error = nfserr_stale; | ||
140 | if (rqstp->rq_vers > 2) | ||
141 | error = nfserr_badhandle; | ||
142 | if (rqstp->rq_vers == 4 && fh->fh_size == 0) | ||
143 | return nfserr_nofilehandle; | ||
144 | |||
145 | if (fh->fh_version == 1) { | ||
146 | int len; | ||
147 | if (--data_left<0) goto out; | ||
148 | switch (fh->fh_auth_type) { | ||
149 | case 0: break; | ||
150 | default: goto out; | ||
151 | } | ||
152 | len = key_len(fh->fh_fsid_type) / 4; | ||
153 | if (len == 0) goto out; | ||
154 | if (fh->fh_fsid_type == FSID_MAJOR_MINOR) { | ||
155 | /* deprecated, convert to type 3 */ | ||
156 | len = key_len(FSID_ENCODE_DEV)/4; | ||
157 | fh->fh_fsid_type = FSID_ENCODE_DEV; | ||
158 | fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1]))); | ||
159 | fh->fh_fsid[1] = fh->fh_fsid[2]; | ||
160 | } | ||
161 | if ((data_left -= len)<0) goto out; | ||
162 | exp = rqst_exp_find(rqstp, fh->fh_fsid_type, | ||
163 | fh->fh_auth); | ||
164 | fid = (struct fid *)(fh->fh_auth + len); | ||
165 | } else { | ||
166 | __u32 tfh[2]; | ||
167 | dev_t xdev; | ||
168 | ino_t xino; | ||
169 | if (fh->fh_size != NFS_FHSIZE) | ||
170 | goto out; | ||
171 | /* assume old filehandle format */ | ||
172 | xdev = old_decode_dev(fh->ofh_xdev); | ||
173 | xino = u32_to_ino_t(fh->ofh_xino); | ||
174 | mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); | ||
175 | exp = rqst_exp_find(rqstp, FSID_DEV, tfh); | ||
176 | } | ||
177 | |||
178 | error = nfserr_stale; | ||
179 | if (PTR_ERR(exp) == -ENOENT) | ||
180 | goto out; | ||
181 | |||
182 | if (IS_ERR(exp)) { | ||
183 | error = nfserrno(PTR_ERR(exp)); | ||
184 | goto out; | ||
185 | } | ||
186 | |||
187 | error = nfsd_setuser_and_check_port(rqstp, exp); | ||
188 | if (error) | 253 | if (error) |
189 | goto out; | 254 | goto out; |
190 | 255 | dentry = fhp->fh_dentry; | |
191 | /* | 256 | exp = fhp->fh_export; |
192 | * Look up the dentry using the NFS file handle. | ||
193 | */ | ||
194 | error = nfserr_stale; | ||
195 | if (rqstp->rq_vers > 2) | ||
196 | error = nfserr_badhandle; | ||
197 | |||
198 | if (fh->fh_version != 1) { | ||
199 | sfid.i32.ino = fh->ofh_ino; | ||
200 | sfid.i32.gen = fh->ofh_generation; | ||
201 | sfid.i32.parent_ino = fh->ofh_dirino; | ||
202 | fid = &sfid; | ||
203 | data_left = 3; | ||
204 | if (fh->ofh_dirino == 0) | ||
205 | fileid_type = FILEID_INO32_GEN; | ||
206 | else | ||
207 | fileid_type = FILEID_INO32_GEN_PARENT; | ||
208 | } else | ||
209 | fileid_type = fh->fh_fileid_type; | ||
210 | |||
211 | if (fileid_type == FILEID_ROOT) | ||
212 | dentry = dget(exp->ex_path.dentry); | ||
213 | else { | ||
214 | dentry = exportfs_decode_fh(exp->ex_path.mnt, fid, | ||
215 | data_left, fileid_type, | ||
216 | nfsd_acceptable, exp); | ||
217 | } | ||
218 | if (dentry == NULL) | ||
219 | goto out; | ||
220 | if (IS_ERR(dentry)) { | ||
221 | if (PTR_ERR(dentry) != -EINVAL) | ||
222 | error = nfserrno(PTR_ERR(dentry)); | ||
223 | goto out; | ||
224 | } | ||
225 | |||
226 | if (S_ISDIR(dentry->d_inode->i_mode) && | ||
227 | (dentry->d_flags & DCACHE_DISCONNECTED)) { | ||
228 | printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n", | ||
229 | dentry->d_parent->d_name.name, dentry->d_name.name); | ||
230 | } | ||
231 | |||
232 | fhp->fh_dentry = dentry; | ||
233 | fhp->fh_export = exp; | ||
234 | nfsd_nr_verified++; | ||
235 | cache_get(&exp->h); | ||
236 | } else { | 257 | } else { |
237 | /* | 258 | /* |
238 | * just rechecking permissions | 259 | * just rechecking permissions |
@@ -242,7 +263,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
242 | dprintk("nfsd: fh_verify - just checking\n"); | 263 | dprintk("nfsd: fh_verify - just checking\n"); |
243 | dentry = fhp->fh_dentry; | 264 | dentry = fhp->fh_dentry; |
244 | exp = fhp->fh_export; | 265 | exp = fhp->fh_export; |
245 | cache_get(&exp->h); | ||
246 | /* | 266 | /* |
247 | * Set user creds for this exportpoint; necessary even | 267 | * Set user creds for this exportpoint; necessary even |
248 | * in the "just checking" case because this may be a | 268 | * in the "just checking" case because this may be a |
@@ -281,8 +301,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
281 | access, ntohl(error)); | 301 | access, ntohl(error)); |
282 | } | 302 | } |
283 | out: | 303 | out: |
284 | if (exp && !IS_ERR(exp)) | ||
285 | exp_put(exp); | ||
286 | if (error == nfserr_stale) | 304 | if (error == nfserr_stale) |
287 | nfsdstats.fh_stale++; | 305 | nfsdstats.fh_stale++; |
288 | return error; | 306 | return error; |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 9647b0f7bc0c..941041f4b136 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -244,7 +244,6 @@ static int nfsd_init_socks(int port) | |||
244 | if (error < 0) | 244 | if (error < 0) |
245 | return error; | 245 | return error; |
246 | 246 | ||
247 | #ifdef CONFIG_NFSD_TCP | ||
248 | error = lockd_up(IPPROTO_TCP); | 247 | error = lockd_up(IPPROTO_TCP); |
249 | if (error >= 0) { | 248 | if (error >= 0) { |
250 | error = svc_create_xprt(nfsd_serv, "tcp", port, | 249 | error = svc_create_xprt(nfsd_serv, "tcp", port, |
@@ -254,7 +253,6 @@ static int nfsd_init_socks(int port) | |||
254 | } | 253 | } |
255 | if (error < 0) | 254 | if (error < 0) |
256 | return error; | 255 | return error; |
257 | #endif | ||
258 | return 0; | 256 | return 0; |
259 | } | 257 | } |
260 | 258 | ||
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 304bf5f643c9..a3a291f771f4 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -264,7 +264,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
264 | struct inode *inode; | 264 | struct inode *inode; |
265 | int accmode = MAY_SATTR; | 265 | int accmode = MAY_SATTR; |
266 | int ftype = 0; | 266 | int ftype = 0; |
267 | int imode; | ||
268 | __be32 err; | 267 | __be32 err; |
269 | int host_err; | 268 | int host_err; |
270 | int size_change = 0; | 269 | int size_change = 0; |
@@ -360,25 +359,25 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
360 | DQUOT_INIT(inode); | 359 | DQUOT_INIT(inode); |
361 | } | 360 | } |
362 | 361 | ||
363 | imode = inode->i_mode; | 362 | /* sanitize the mode change */ |
364 | if (iap->ia_valid & ATTR_MODE) { | 363 | if (iap->ia_valid & ATTR_MODE) { |
365 | iap->ia_mode &= S_IALLUGO; | 364 | iap->ia_mode &= S_IALLUGO; |
366 | imode = iap->ia_mode |= (imode & ~S_IALLUGO); | 365 | iap->ia_mode |= (inode->i_mode & ~S_IALLUGO); |
367 | /* if changing uid/gid revoke setuid/setgid in mode */ | 366 | } |
368 | if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) { | 367 | |
369 | iap->ia_valid |= ATTR_KILL_PRIV; | 368 | /* Revoke setuid/setgid on chown */ |
369 | if (((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) || | ||
370 | ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)) { | ||
371 | iap->ia_valid |= ATTR_KILL_PRIV; | ||
372 | if (iap->ia_valid & ATTR_MODE) { | ||
373 | /* we're setting mode too, just clear the s*id bits */ | ||
370 | iap->ia_mode &= ~S_ISUID; | 374 | iap->ia_mode &= ~S_ISUID; |
375 | if (iap->ia_mode & S_IXGRP) | ||
376 | iap->ia_mode &= ~S_ISGID; | ||
377 | } else { | ||
378 | /* set ATTR_KILL_* bits and let VFS handle it */ | ||
379 | iap->ia_valid |= (ATTR_KILL_SUID | ATTR_KILL_SGID); | ||
371 | } | 380 | } |
372 | if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid) | ||
373 | iap->ia_mode &= ~S_ISGID; | ||
374 | } else { | ||
375 | /* | ||
376 | * Revoke setuid/setgid bit on chown/chgrp | ||
377 | */ | ||
378 | if ((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) | ||
379 | iap->ia_valid |= ATTR_KILL_SUID | ATTR_KILL_PRIV; | ||
380 | if ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid) | ||
381 | iap->ia_valid |= ATTR_KILL_SGID; | ||
382 | } | 381 | } |
383 | 382 | ||
384 | /* Change the attributes. */ | 383 | /* Change the attributes. */ |
@@ -988,7 +987,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
988 | * flushing the data to disk is handled separately below. | 987 | * flushing the data to disk is handled separately below. |
989 | */ | 988 | */ |
990 | 989 | ||
991 | if (file->f_op->fsync == 0) {/* COMMIT3 cannot work */ | 990 | if (!file->f_op->fsync) {/* COMMIT3 cannot work */ |
992 | stable = 2; | 991 | stable = 2; |
993 | *stablep = 2; /* FILE_SYNC */ | 992 | *stablep = 2; /* FILE_SYNC */ |
994 | } | 993 | } |
@@ -1152,7 +1151,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1152 | } | 1151 | } |
1153 | #endif /* CONFIG_NFSD_V3 */ | 1152 | #endif /* CONFIG_NFSD_V3 */ |
1154 | 1153 | ||
1155 | __be32 | 1154 | static __be32 |
1156 | nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp, | 1155 | nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp, |
1157 | struct iattr *iap) | 1156 | struct iattr *iap) |
1158 | { | 1157 | { |
@@ -988,7 +988,10 @@ struct file *create_write_pipe(void) | |||
988 | return f; | 988 | return f; |
989 | 989 | ||
990 | err_dentry: | 990 | err_dentry: |
991 | free_pipe_info(inode); | ||
991 | dput(dentry); | 992 | dput(dentry); |
993 | return ERR_PTR(err); | ||
994 | |||
992 | err_inode: | 995 | err_inode: |
993 | free_pipe_info(inode); | 996 | free_pipe_info(inode); |
994 | iput(inode); | 997 | iput(inode); |
diff --git a/fs/pnode.c b/fs/pnode.c index 1d8f5447f3f7..8d5f392ec3d3 100644 --- a/fs/pnode.c +++ b/fs/pnode.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/mnt_namespace.h> | 9 | #include <linux/mnt_namespace.h> |
10 | #include <linux/mount.h> | 10 | #include <linux/mount.h> |
11 | #include <linux/fs.h> | 11 | #include <linux/fs.h> |
12 | #include "internal.h" | ||
12 | #include "pnode.h" | 13 | #include "pnode.h" |
13 | 14 | ||
14 | /* return the next shared peer mount of @p */ | 15 | /* return the next shared peer mount of @p */ |
@@ -27,6 +28,57 @@ static inline struct vfsmount *next_slave(struct vfsmount *p) | |||
27 | return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave); | 28 | return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave); |
28 | } | 29 | } |
29 | 30 | ||
31 | /* | ||
32 | * Return true if path is reachable from root | ||
33 | * | ||
34 | * namespace_sem is held, and mnt is attached | ||
35 | */ | ||
36 | static bool is_path_reachable(struct vfsmount *mnt, struct dentry *dentry, | ||
37 | const struct path *root) | ||
38 | { | ||
39 | while (mnt != root->mnt && mnt->mnt_parent != mnt) { | ||
40 | dentry = mnt->mnt_mountpoint; | ||
41 | mnt = mnt->mnt_parent; | ||
42 | } | ||
43 | return mnt == root->mnt && is_subdir(dentry, root->dentry); | ||
44 | } | ||
45 | |||
46 | static struct vfsmount *get_peer_under_root(struct vfsmount *mnt, | ||
47 | struct mnt_namespace *ns, | ||
48 | const struct path *root) | ||
49 | { | ||
50 | struct vfsmount *m = mnt; | ||
51 | |||
52 | do { | ||
53 | /* Check the namespace first for optimization */ | ||
54 | if (m->mnt_ns == ns && is_path_reachable(m, m->mnt_root, root)) | ||
55 | return m; | ||
56 | |||
57 | m = next_peer(m); | ||
58 | } while (m != mnt); | ||
59 | |||
60 | return NULL; | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | * Get ID of closest dominating peer group having a representative | ||
65 | * under the given root. | ||
66 | * | ||
67 | * Caller must hold namespace_sem | ||
68 | */ | ||
69 | int get_dominating_id(struct vfsmount *mnt, const struct path *root) | ||
70 | { | ||
71 | struct vfsmount *m; | ||
72 | |||
73 | for (m = mnt->mnt_master; m != NULL; m = m->mnt_master) { | ||
74 | struct vfsmount *d = get_peer_under_root(m, mnt->mnt_ns, root); | ||
75 | if (d) | ||
76 | return d->mnt_group_id; | ||
77 | } | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
30 | static int do_make_slave(struct vfsmount *mnt) | 82 | static int do_make_slave(struct vfsmount *mnt) |
31 | { | 83 | { |
32 | struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; | 84 | struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; |
@@ -45,7 +97,11 @@ static int do_make_slave(struct vfsmount *mnt) | |||
45 | if (peer_mnt == mnt) | 97 | if (peer_mnt == mnt) |
46 | peer_mnt = NULL; | 98 | peer_mnt = NULL; |
47 | } | 99 | } |
100 | if (IS_MNT_SHARED(mnt) && list_empty(&mnt->mnt_share)) | ||
101 | mnt_release_group_id(mnt); | ||
102 | |||
48 | list_del_init(&mnt->mnt_share); | 103 | list_del_init(&mnt->mnt_share); |
104 | mnt->mnt_group_id = 0; | ||
49 | 105 | ||
50 | if (peer_mnt) | 106 | if (peer_mnt) |
51 | master = peer_mnt; | 107 | master = peer_mnt; |
@@ -67,7 +123,6 @@ static int do_make_slave(struct vfsmount *mnt) | |||
67 | } | 123 | } |
68 | mnt->mnt_master = master; | 124 | mnt->mnt_master = master; |
69 | CLEAR_MNT_SHARED(mnt); | 125 | CLEAR_MNT_SHARED(mnt); |
70 | INIT_LIST_HEAD(&mnt->mnt_slave_list); | ||
71 | return 0; | 126 | return 0; |
72 | } | 127 | } |
73 | 128 | ||
@@ -211,8 +266,7 @@ int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry, | |||
211 | out: | 266 | out: |
212 | spin_lock(&vfsmount_lock); | 267 | spin_lock(&vfsmount_lock); |
213 | while (!list_empty(&tmp_list)) { | 268 | while (!list_empty(&tmp_list)) { |
214 | child = list_entry(tmp_list.next, struct vfsmount, mnt_hash); | 269 | child = list_first_entry(&tmp_list, struct vfsmount, mnt_hash); |
215 | list_del_init(&child->mnt_hash); | ||
216 | umount_tree(child, 0, &umount_list); | 270 | umount_tree(child, 0, &umount_list); |
217 | } | 271 | } |
218 | spin_unlock(&vfsmount_lock); | 272 | spin_unlock(&vfsmount_lock); |
diff --git a/fs/pnode.h b/fs/pnode.h index f249be2fee7a..958665d662af 100644 --- a/fs/pnode.h +++ b/fs/pnode.h | |||
@@ -35,4 +35,6 @@ int propagate_mnt(struct vfsmount *, struct dentry *, struct vfsmount *, | |||
35 | struct list_head *); | 35 | struct list_head *); |
36 | int propagate_umount(struct list_head *); | 36 | int propagate_umount(struct list_head *); |
37 | int propagate_mount_busy(struct vfsmount *, int); | 37 | int propagate_mount_busy(struct vfsmount *, int); |
38 | void mnt_release_group_id(struct vfsmount *); | ||
39 | int get_dominating_id(struct vfsmount *mnt, const struct path *root); | ||
38 | #endif /* _LINUX_PNODE_H */ | 40 | #endif /* _LINUX_PNODE_H */ |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 81d7d145292a..c5e412a00b17 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -502,17 +502,14 @@ static const struct inode_operations proc_def_inode_operations = { | |||
502 | .setattr = proc_setattr, | 502 | .setattr = proc_setattr, |
503 | }; | 503 | }; |
504 | 504 | ||
505 | extern const struct seq_operations mounts_op; | 505 | static int mounts_open_common(struct inode *inode, struct file *file, |
506 | struct proc_mounts { | 506 | const struct seq_operations *op) |
507 | struct seq_file m; | ||
508 | int event; | ||
509 | }; | ||
510 | |||
511 | static int mounts_open(struct inode *inode, struct file *file) | ||
512 | { | 507 | { |
513 | struct task_struct *task = get_proc_task(inode); | 508 | struct task_struct *task = get_proc_task(inode); |
514 | struct nsproxy *nsp; | 509 | struct nsproxy *nsp; |
515 | struct mnt_namespace *ns = NULL; | 510 | struct mnt_namespace *ns = NULL; |
511 | struct fs_struct *fs = NULL; | ||
512 | struct path root; | ||
516 | struct proc_mounts *p; | 513 | struct proc_mounts *p; |
517 | int ret = -EINVAL; | 514 | int ret = -EINVAL; |
518 | 515 | ||
@@ -525,40 +522,61 @@ static int mounts_open(struct inode *inode, struct file *file) | |||
525 | get_mnt_ns(ns); | 522 | get_mnt_ns(ns); |
526 | } | 523 | } |
527 | rcu_read_unlock(); | 524 | rcu_read_unlock(); |
528 | 525 | if (ns) | |
526 | fs = get_fs_struct(task); | ||
529 | put_task_struct(task); | 527 | put_task_struct(task); |
530 | } | 528 | } |
531 | 529 | ||
532 | if (ns) { | 530 | if (!ns) |
533 | ret = -ENOMEM; | 531 | goto err; |
534 | p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); | 532 | if (!fs) |
535 | if (p) { | 533 | goto err_put_ns; |
536 | file->private_data = &p->m; | 534 | |
537 | ret = seq_open(file, &mounts_op); | 535 | read_lock(&fs->lock); |
538 | if (!ret) { | 536 | root = fs->root; |
539 | p->m.private = ns; | 537 | path_get(&root); |
540 | p->event = ns->event; | 538 | read_unlock(&fs->lock); |
541 | return 0; | 539 | put_fs_struct(fs); |
542 | } | 540 | |
543 | kfree(p); | 541 | ret = -ENOMEM; |
544 | } | 542 | p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); |
545 | put_mnt_ns(ns); | 543 | if (!p) |
546 | } | 544 | goto err_put_path; |
545 | |||
546 | file->private_data = &p->m; | ||
547 | ret = seq_open(file, op); | ||
548 | if (ret) | ||
549 | goto err_free; | ||
550 | |||
551 | p->m.private = p; | ||
552 | p->ns = ns; | ||
553 | p->root = root; | ||
554 | p->event = ns->event; | ||
555 | |||
556 | return 0; | ||
557 | |||
558 | err_free: | ||
559 | kfree(p); | ||
560 | err_put_path: | ||
561 | path_put(&root); | ||
562 | err_put_ns: | ||
563 | put_mnt_ns(ns); | ||
564 | err: | ||
547 | return ret; | 565 | return ret; |
548 | } | 566 | } |
549 | 567 | ||
550 | static int mounts_release(struct inode *inode, struct file *file) | 568 | static int mounts_release(struct inode *inode, struct file *file) |
551 | { | 569 | { |
552 | struct seq_file *m = file->private_data; | 570 | struct proc_mounts *p = file->private_data; |
553 | struct mnt_namespace *ns = m->private; | 571 | path_put(&p->root); |
554 | put_mnt_ns(ns); | 572 | put_mnt_ns(p->ns); |
555 | return seq_release(inode, file); | 573 | return seq_release(inode, file); |
556 | } | 574 | } |
557 | 575 | ||
558 | static unsigned mounts_poll(struct file *file, poll_table *wait) | 576 | static unsigned mounts_poll(struct file *file, poll_table *wait) |
559 | { | 577 | { |
560 | struct proc_mounts *p = file->private_data; | 578 | struct proc_mounts *p = file->private_data; |
561 | struct mnt_namespace *ns = p->m.private; | 579 | struct mnt_namespace *ns = p->ns; |
562 | unsigned res = 0; | 580 | unsigned res = 0; |
563 | 581 | ||
564 | poll_wait(file, &ns->poll, wait); | 582 | poll_wait(file, &ns->poll, wait); |
@@ -573,6 +591,11 @@ static unsigned mounts_poll(struct file *file, poll_table *wait) | |||
573 | return res; | 591 | return res; |
574 | } | 592 | } |
575 | 593 | ||
594 | static int mounts_open(struct inode *inode, struct file *file) | ||
595 | { | ||
596 | return mounts_open_common(inode, file, &mounts_op); | ||
597 | } | ||
598 | |||
576 | static const struct file_operations proc_mounts_operations = { | 599 | static const struct file_operations proc_mounts_operations = { |
577 | .open = mounts_open, | 600 | .open = mounts_open, |
578 | .read = seq_read, | 601 | .read = seq_read, |
@@ -581,38 +604,22 @@ static const struct file_operations proc_mounts_operations = { | |||
581 | .poll = mounts_poll, | 604 | .poll = mounts_poll, |
582 | }; | 605 | }; |
583 | 606 | ||
584 | extern const struct seq_operations mountstats_op; | 607 | static int mountinfo_open(struct inode *inode, struct file *file) |
585 | static int mountstats_open(struct inode *inode, struct file *file) | ||
586 | { | 608 | { |
587 | int ret = seq_open(file, &mountstats_op); | 609 | return mounts_open_common(inode, file, &mountinfo_op); |
588 | 610 | } | |
589 | if (!ret) { | ||
590 | struct seq_file *m = file->private_data; | ||
591 | struct nsproxy *nsp; | ||
592 | struct mnt_namespace *mnt_ns = NULL; | ||
593 | struct task_struct *task = get_proc_task(inode); | ||
594 | |||
595 | if (task) { | ||
596 | rcu_read_lock(); | ||
597 | nsp = task_nsproxy(task); | ||
598 | if (nsp) { | ||
599 | mnt_ns = nsp->mnt_ns; | ||
600 | if (mnt_ns) | ||
601 | get_mnt_ns(mnt_ns); | ||
602 | } | ||
603 | rcu_read_unlock(); | ||
604 | 611 | ||
605 | put_task_struct(task); | 612 | static const struct file_operations proc_mountinfo_operations = { |
606 | } | 613 | .open = mountinfo_open, |
614 | .read = seq_read, | ||
615 | .llseek = seq_lseek, | ||
616 | .release = mounts_release, | ||
617 | .poll = mounts_poll, | ||
618 | }; | ||
607 | 619 | ||
608 | if (mnt_ns) | 620 | static int mountstats_open(struct inode *inode, struct file *file) |
609 | m->private = mnt_ns; | 621 | { |
610 | else { | 622 | return mounts_open_common(inode, file, &mountstats_op); |
611 | seq_release(inode, file); | ||
612 | ret = -EINVAL; | ||
613 | } | ||
614 | } | ||
615 | return ret; | ||
616 | } | 623 | } |
617 | 624 | ||
618 | static const struct file_operations proc_mountstats_operations = { | 625 | static const struct file_operations proc_mountstats_operations = { |
@@ -1626,7 +1633,6 @@ static int proc_readfd_common(struct file * filp, void * dirent, | |||
1626 | unsigned int fd, ino; | 1633 | unsigned int fd, ino; |
1627 | int retval; | 1634 | int retval; |
1628 | struct files_struct * files; | 1635 | struct files_struct * files; |
1629 | struct fdtable *fdt; | ||
1630 | 1636 | ||
1631 | retval = -ENOENT; | 1637 | retval = -ENOENT; |
1632 | if (!p) | 1638 | if (!p) |
@@ -1649,9 +1655,8 @@ static int proc_readfd_common(struct file * filp, void * dirent, | |||
1649 | if (!files) | 1655 | if (!files) |
1650 | goto out; | 1656 | goto out; |
1651 | rcu_read_lock(); | 1657 | rcu_read_lock(); |
1652 | fdt = files_fdtable(files); | ||
1653 | for (fd = filp->f_pos-2; | 1658 | for (fd = filp->f_pos-2; |
1654 | fd < fdt->max_fds; | 1659 | fd < files_fdtable(files)->max_fds; |
1655 | fd++, filp->f_pos++) { | 1660 | fd++, filp->f_pos++) { |
1656 | char name[PROC_NUMBUF]; | 1661 | char name[PROC_NUMBUF]; |
1657 | int len; | 1662 | int len; |
@@ -2311,6 +2316,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2311 | LNK("root", root), | 2316 | LNK("root", root), |
2312 | LNK("exe", exe), | 2317 | LNK("exe", exe), |
2313 | REG("mounts", S_IRUGO, mounts), | 2318 | REG("mounts", S_IRUGO, mounts), |
2319 | REG("mountinfo", S_IRUGO, mountinfo), | ||
2314 | REG("mountstats", S_IRUSR, mountstats), | 2320 | REG("mountstats", S_IRUSR, mountstats), |
2315 | #ifdef CONFIG_PROC_PAGE_MONITOR | 2321 | #ifdef CONFIG_PROC_PAGE_MONITOR |
2316 | REG("clear_refs", S_IWUSR, clear_refs), | 2322 | REG("clear_refs", S_IWUSR, clear_refs), |
@@ -2643,6 +2649,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
2643 | LNK("root", root), | 2649 | LNK("root", root), |
2644 | LNK("exe", exe), | 2650 | LNK("exe", exe), |
2645 | REG("mounts", S_IRUGO, mounts), | 2651 | REG("mounts", S_IRUGO, mounts), |
2652 | REG("mountinfo", S_IRUGO, mountinfo), | ||
2646 | #ifdef CONFIG_PROC_PAGE_MONITOR | 2653 | #ifdef CONFIG_PROC_PAGE_MONITOR |
2647 | REG("clear_refs", S_IWUSR, clear_refs), | 2654 | REG("clear_refs", S_IWUSR, clear_refs), |
2648 | REG("smaps", S_IRUGO, smaps), | 2655 | REG("smaps", S_IRUGO, smaps), |
diff --git a/fs/read_write.c b/fs/read_write.c index 49a98718ecdf..f0d1240a5c69 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -33,7 +33,7 @@ EXPORT_SYMBOL(generic_ro_fops); | |||
33 | 33 | ||
34 | loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) | 34 | loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) |
35 | { | 35 | { |
36 | long long retval; | 36 | loff_t retval; |
37 | struct inode *inode = file->f_mapping->host; | 37 | struct inode *inode = file->f_mapping->host; |
38 | 38 | ||
39 | mutex_lock(&inode->i_mutex); | 39 | mutex_lock(&inode->i_mutex); |
@@ -60,7 +60,7 @@ EXPORT_SYMBOL(generic_file_llseek); | |||
60 | 60 | ||
61 | loff_t remote_llseek(struct file *file, loff_t offset, int origin) | 61 | loff_t remote_llseek(struct file *file, loff_t offset, int origin) |
62 | { | 62 | { |
63 | long long retval; | 63 | loff_t retval; |
64 | 64 | ||
65 | lock_kernel(); | 65 | lock_kernel(); |
66 | switch (origin) { | 66 | switch (origin) { |
@@ -91,7 +91,7 @@ EXPORT_SYMBOL(no_llseek); | |||
91 | 91 | ||
92 | loff_t default_llseek(struct file *file, loff_t offset, int origin) | 92 | loff_t default_llseek(struct file *file, loff_t offset, int origin) |
93 | { | 93 | { |
94 | long long retval; | 94 | loff_t retval; |
95 | 95 | ||
96 | lock_kernel(); | 96 | lock_kernel(); |
97 | switch (origin) { | 97 | switch (origin) { |
diff --git a/fs/seq_file.c b/fs/seq_file.c index 853770274f20..3f54dbd6c49b 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c | |||
@@ -25,6 +25,7 @@ | |||
25 | * into the buffer. In case of error ->start() and ->next() return | 25 | * into the buffer. In case of error ->start() and ->next() return |
26 | * ERR_PTR(error). In the end of sequence they return %NULL. ->show() | 26 | * ERR_PTR(error). In the end of sequence they return %NULL. ->show() |
27 | * returns 0 in case of success and negative number in case of error. | 27 | * returns 0 in case of success and negative number in case of error. |
28 | * Returning SEQ_SKIP means "discard this element and move on". | ||
28 | */ | 29 | */ |
29 | int seq_open(struct file *file, const struct seq_operations *op) | 30 | int seq_open(struct file *file, const struct seq_operations *op) |
30 | { | 31 | { |
@@ -114,8 +115,10 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) | |||
114 | if (!p || IS_ERR(p)) | 115 | if (!p || IS_ERR(p)) |
115 | break; | 116 | break; |
116 | err = m->op->show(m, p); | 117 | err = m->op->show(m, p); |
117 | if (err) | 118 | if (err < 0) |
118 | break; | 119 | break; |
120 | if (unlikely(err)) | ||
121 | m->count = 0; | ||
119 | if (m->count < m->size) | 122 | if (m->count < m->size) |
120 | goto Fill; | 123 | goto Fill; |
121 | m->op->stop(m, p); | 124 | m->op->stop(m, p); |
@@ -140,9 +143,10 @@ Fill: | |||
140 | break; | 143 | break; |
141 | } | 144 | } |
142 | err = m->op->show(m, p); | 145 | err = m->op->show(m, p); |
143 | if (err || m->count == m->size) { | 146 | if (m->count == m->size || err) { |
144 | m->count = offs; | 147 | m->count = offs; |
145 | break; | 148 | if (likely(err <= 0)) |
149 | break; | ||
146 | } | 150 | } |
147 | pos = next; | 151 | pos = next; |
148 | } | 152 | } |
@@ -199,8 +203,12 @@ static int traverse(struct seq_file *m, loff_t offset) | |||
199 | if (IS_ERR(p)) | 203 | if (IS_ERR(p)) |
200 | break; | 204 | break; |
201 | error = m->op->show(m, p); | 205 | error = m->op->show(m, p); |
202 | if (error) | 206 | if (error < 0) |
203 | break; | 207 | break; |
208 | if (unlikely(error)) { | ||
209 | error = 0; | ||
210 | m->count = 0; | ||
211 | } | ||
204 | if (m->count == m->size) | 212 | if (m->count == m->size) |
205 | goto Eoverflow; | 213 | goto Eoverflow; |
206 | if (pos + m->count > offset) { | 214 | if (pos + m->count > offset) { |
@@ -239,7 +247,7 @@ Eoverflow: | |||
239 | loff_t seq_lseek(struct file *file, loff_t offset, int origin) | 247 | loff_t seq_lseek(struct file *file, loff_t offset, int origin) |
240 | { | 248 | { |
241 | struct seq_file *m = (struct seq_file *)file->private_data; | 249 | struct seq_file *m = (struct seq_file *)file->private_data; |
242 | long long retval = -EINVAL; | 250 | loff_t retval = -EINVAL; |
243 | 251 | ||
244 | mutex_lock(&m->lock); | 252 | mutex_lock(&m->lock); |
245 | m->version = file->f_version; | 253 | m->version = file->f_version; |
@@ -342,28 +350,40 @@ int seq_printf(struct seq_file *m, const char *f, ...) | |||
342 | } | 350 | } |
343 | EXPORT_SYMBOL(seq_printf); | 351 | EXPORT_SYMBOL(seq_printf); |
344 | 352 | ||
353 | static char *mangle_path(char *s, char *p, char *esc) | ||
354 | { | ||
355 | while (s <= p) { | ||
356 | char c = *p++; | ||
357 | if (!c) { | ||
358 | return s; | ||
359 | } else if (!strchr(esc, c)) { | ||
360 | *s++ = c; | ||
361 | } else if (s + 4 > p) { | ||
362 | break; | ||
363 | } else { | ||
364 | *s++ = '\\'; | ||
365 | *s++ = '0' + ((c & 0300) >> 6); | ||
366 | *s++ = '0' + ((c & 070) >> 3); | ||
367 | *s++ = '0' + (c & 07); | ||
368 | } | ||
369 | } | ||
370 | return NULL; | ||
371 | } | ||
372 | |||
373 | /* | ||
374 | * return the absolute path of 'dentry' residing in mount 'mnt'. | ||
375 | */ | ||
345 | int seq_path(struct seq_file *m, struct path *path, char *esc) | 376 | int seq_path(struct seq_file *m, struct path *path, char *esc) |
346 | { | 377 | { |
347 | if (m->count < m->size) { | 378 | if (m->count < m->size) { |
348 | char *s = m->buf + m->count; | 379 | char *s = m->buf + m->count; |
349 | char *p = d_path(path, s, m->size - m->count); | 380 | char *p = d_path(path, s, m->size - m->count); |
350 | if (!IS_ERR(p)) { | 381 | if (!IS_ERR(p)) { |
351 | while (s <= p) { | 382 | s = mangle_path(s, p, esc); |
352 | char c = *p++; | 383 | if (s) { |
353 | if (!c) { | 384 | p = m->buf + m->count; |
354 | p = m->buf + m->count; | 385 | m->count = s - m->buf; |
355 | m->count = s - m->buf; | 386 | return s - p; |
356 | return s - p; | ||
357 | } else if (!strchr(esc, c)) { | ||
358 | *s++ = c; | ||
359 | } else if (s + 4 > p) { | ||
360 | break; | ||
361 | } else { | ||
362 | *s++ = '\\'; | ||
363 | *s++ = '0' + ((c & 0300) >> 6); | ||
364 | *s++ = '0' + ((c & 070) >> 3); | ||
365 | *s++ = '0' + (c & 07); | ||
366 | } | ||
367 | } | 387 | } |
368 | } | 388 | } |
369 | } | 389 | } |
@@ -372,6 +392,57 @@ int seq_path(struct seq_file *m, struct path *path, char *esc) | |||
372 | } | 392 | } |
373 | EXPORT_SYMBOL(seq_path); | 393 | EXPORT_SYMBOL(seq_path); |
374 | 394 | ||
395 | /* | ||
396 | * Same as seq_path, but relative to supplied root. | ||
397 | * | ||
398 | * root may be changed, see __d_path(). | ||
399 | */ | ||
400 | int seq_path_root(struct seq_file *m, struct path *path, struct path *root, | ||
401 | char *esc) | ||
402 | { | ||
403 | int err = -ENAMETOOLONG; | ||
404 | if (m->count < m->size) { | ||
405 | char *s = m->buf + m->count; | ||
406 | char *p; | ||
407 | |||
408 | spin_lock(&dcache_lock); | ||
409 | p = __d_path(path, root, s, m->size - m->count); | ||
410 | spin_unlock(&dcache_lock); | ||
411 | err = PTR_ERR(p); | ||
412 | if (!IS_ERR(p)) { | ||
413 | s = mangle_path(s, p, esc); | ||
414 | if (s) { | ||
415 | p = m->buf + m->count; | ||
416 | m->count = s - m->buf; | ||
417 | return 0; | ||
418 | } | ||
419 | } | ||
420 | } | ||
421 | m->count = m->size; | ||
422 | return err; | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * returns the path of the 'dentry' from the root of its filesystem. | ||
427 | */ | ||
428 | int seq_dentry(struct seq_file *m, struct dentry *dentry, char *esc) | ||
429 | { | ||
430 | if (m->count < m->size) { | ||
431 | char *s = m->buf + m->count; | ||
432 | char *p = dentry_path(dentry, s, m->size - m->count); | ||
433 | if (!IS_ERR(p)) { | ||
434 | s = mangle_path(s, p, esc); | ||
435 | if (s) { | ||
436 | p = m->buf + m->count; | ||
437 | m->count = s - m->buf; | ||
438 | return s - p; | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | m->count = m->size; | ||
443 | return -1; | ||
444 | } | ||
445 | |||
375 | static void *single_start(struct seq_file *p, loff_t *pos) | 446 | static void *single_start(struct seq_file *p, loff_t *pos) |
376 | { | 447 | { |
377 | return NULL + (*pos == 0); | 448 | return NULL + (*pos == 0); |
diff --git a/fs/super.c b/fs/super.c index 1f8f05ede437..4798350b2bc9 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/mutex.h> | 39 | #include <linux/mutex.h> |
40 | #include <linux/file.h> | 40 | #include <linux/file.h> |
41 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
42 | #include "internal.h" | ||
42 | 43 | ||
43 | 44 | ||
44 | LIST_HEAD(super_blocks); | 45 | LIST_HEAD(super_blocks); |
diff --git a/fs/udf/Makefile b/fs/udf/Makefile index be845e7540ef..0d4503f7446d 100644 --- a/fs/udf/Makefile +++ b/fs/udf/Makefile | |||
@@ -6,4 +6,4 @@ obj-$(CONFIG_UDF_FS) += udf.o | |||
6 | 6 | ||
7 | udf-objs := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \ | 7 | udf-objs := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \ |
8 | partition.o super.o truncate.o symlink.o fsync.o \ | 8 | partition.o super.o truncate.o symlink.o fsync.o \ |
9 | crc.o directory.o misc.o udftime.o unicode.o | 9 | directory.o misc.o udftime.o unicode.o |
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index f855dcbbdfb8..1b809bd494bd 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c | |||
@@ -149,8 +149,7 @@ static bool udf_add_free_space(struct udf_sb_info *sbi, | |||
149 | return false; | 149 | return false; |
150 | 150 | ||
151 | lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data; | 151 | lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data; |
152 | lvid->freeSpaceTable[partition] = cpu_to_le32(le32_to_cpu( | 152 | le32_add_cpu(&lvid->freeSpaceTable[partition], cnt); |
153 | lvid->freeSpaceTable[partition]) + cnt); | ||
154 | return true; | 153 | return true; |
155 | } | 154 | } |
156 | 155 | ||
@@ -589,10 +588,8 @@ static void udf_table_free_blocks(struct super_block *sb, | |||
589 | sptr = oepos.bh->b_data + epos.offset; | 588 | sptr = oepos.bh->b_data + epos.offset; |
590 | aed = (struct allocExtDesc *) | 589 | aed = (struct allocExtDesc *) |
591 | oepos.bh->b_data; | 590 | oepos.bh->b_data; |
592 | aed->lengthAllocDescs = | 591 | le32_add_cpu(&aed->lengthAllocDescs, |
593 | cpu_to_le32(le32_to_cpu( | 592 | adsize); |
594 | aed->lengthAllocDescs) + | ||
595 | adsize); | ||
596 | } else { | 593 | } else { |
597 | sptr = iinfo->i_ext.i_data + | 594 | sptr = iinfo->i_ext.i_data + |
598 | epos.offset; | 595 | epos.offset; |
@@ -645,9 +642,7 @@ static void udf_table_free_blocks(struct super_block *sb, | |||
645 | mark_inode_dirty(table); | 642 | mark_inode_dirty(table); |
646 | } else { | 643 | } else { |
647 | aed = (struct allocExtDesc *)epos.bh->b_data; | 644 | aed = (struct allocExtDesc *)epos.bh->b_data; |
648 | aed->lengthAllocDescs = | 645 | le32_add_cpu(&aed->lengthAllocDescs, adsize); |
649 | cpu_to_le32(le32_to_cpu( | ||
650 | aed->lengthAllocDescs) + adsize); | ||
651 | udf_update_tag(epos.bh->b_data, epos.offset); | 646 | udf_update_tag(epos.bh->b_data, epos.offset); |
652 | mark_buffer_dirty(epos.bh); | 647 | mark_buffer_dirty(epos.bh); |
653 | } | 648 | } |
diff --git a/fs/udf/crc.c b/fs/udf/crc.c deleted file mode 100644 index b1661296e786..000000000000 --- a/fs/udf/crc.c +++ /dev/null | |||
@@ -1,172 +0,0 @@ | |||
1 | /* | ||
2 | * crc.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Routines to generate, calculate, and test a 16-bit CRC. | ||
6 | * | ||
7 | * DESCRIPTION | ||
8 | * The CRC code was devised by Don P. Mitchell of AT&T Bell Laboratories | ||
9 | * and Ned W. Rhodes of Software Systems Group. It has been published in | ||
10 | * "Design and Validation of Computer Protocols", Prentice Hall, | ||
11 | * Englewood Cliffs, NJ, 1991, Chapter 3, ISBN 0-13-539925-4. | ||
12 | * | ||
13 | * Copyright is held by AT&T. | ||
14 | * | ||
15 | * AT&T gives permission for the free use of the CRC source code. | ||
16 | * | ||
17 | * COPYRIGHT | ||
18 | * This file is distributed under the terms of the GNU General Public | ||
19 | * License (GPL). Copies of the GPL can be obtained from: | ||
20 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
21 | * Each contributing author retains all rights to their own work. | ||
22 | */ | ||
23 | |||
24 | #include "udfdecl.h" | ||
25 | |||
26 | static uint16_t crc_table[256] = { | ||
27 | 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U, | ||
28 | 0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU, | ||
29 | 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U, | ||
30 | 0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU, | ||
31 | 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U, | ||
32 | 0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU, | ||
33 | 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U, | ||
34 | 0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU, | ||
35 | 0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U, | ||
36 | 0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU, | ||
37 | 0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U, | ||
38 | 0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU, | ||
39 | 0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U, | ||
40 | 0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U, | ||
41 | 0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U, | ||
42 | 0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U, | ||
43 | 0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU, | ||
44 | 0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U, | ||
45 | 0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU, | ||
46 | 0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U, | ||
47 | 0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU, | ||
48 | 0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U, | ||
49 | 0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU, | ||
50 | 0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U, | ||
51 | 0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU, | ||
52 | 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U, | ||
53 | 0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU, | ||
54 | 0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U, | ||
55 | 0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U, | ||
56 | 0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U, | ||
57 | 0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U, | ||
58 | 0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U | ||
59 | }; | ||
60 | |||
61 | /* | ||
62 | * udf_crc | ||
63 | * | ||
64 | * PURPOSE | ||
65 | * Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial. | ||
66 | * | ||
67 | * DESCRIPTION | ||
68 | * The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory. | ||
69 | * The polynomial used is: x^16 + x^12 + x^15 + 1 | ||
70 | * | ||
71 | * PRE-CONDITIONS | ||
72 | * data Pointer to the data block. | ||
73 | * size Size of the data block. | ||
74 | * | ||
75 | * POST-CONDITIONS | ||
76 | * <return> CRC of the data block. | ||
77 | * | ||
78 | * HISTORY | ||
79 | * July 21, 1997 - Andrew E. Mileski | ||
80 | * Adapted from OSTA-UDF(tm) 1.50 standard. | ||
81 | */ | ||
82 | uint16_t udf_crc(uint8_t *data, uint32_t size, uint16_t crc) | ||
83 | { | ||
84 | while (size--) | ||
85 | crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8); | ||
86 | |||
87 | return crc; | ||
88 | } | ||
89 | |||
90 | /****************************************************************************/ | ||
91 | #if defined(TEST) | ||
92 | |||
93 | /* | ||
94 | * PURPOSE | ||
95 | * Test udf_crc() | ||
96 | * | ||
97 | * HISTORY | ||
98 | * July 21, 1997 - Andrew E. Mileski | ||
99 | * Adapted from OSTA-UDF(tm) 1.50 standard. | ||
100 | */ | ||
101 | |||
102 | unsigned char bytes[] = { 0x70U, 0x6AU, 0x77U }; | ||
103 | |||
104 | int main(void) | ||
105 | { | ||
106 | unsigned short x; | ||
107 | |||
108 | x = udf_crc(bytes, sizeof bytes); | ||
109 | printf("udf_crc: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U); | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | #endif /* defined(TEST) */ | ||
115 | |||
116 | /****************************************************************************/ | ||
117 | #if defined(GENERATE) | ||
118 | |||
119 | /* | ||
120 | * PURPOSE | ||
121 | * Generate a table for fast 16-bit CRC calculations (any polynomial). | ||
122 | * | ||
123 | * DESCRIPTION | ||
124 | * The ITU-T V.41 polynomial is 010041. | ||
125 | * | ||
126 | * HISTORY | ||
127 | * July 21, 1997 - Andrew E. Mileski | ||
128 | * Adapted from OSTA-UDF(tm) 1.50 standard. | ||
129 | */ | ||
130 | |||
131 | #include <stdio.h> | ||
132 | |||
133 | int main(int argc, char **argv) | ||
134 | { | ||
135 | unsigned long crc, poly; | ||
136 | int n, i; | ||
137 | |||
138 | /* Get the polynomial */ | ||
139 | sscanf(argv[1], "%lo", &poly); | ||
140 | if (poly & 0xffff0000U) { | ||
141 | fprintf(stderr, "polynomial is too large\en"); | ||
142 | exit(1); | ||
143 | } | ||
144 | |||
145 | printf("/* CRC 0%o */\n", poly); | ||
146 | |||
147 | /* Create a table */ | ||
148 | printf("static unsigned short crc_table[256] = {\n"); | ||
149 | for (n = 0; n < 256; n++) { | ||
150 | if (n % 8 == 0) | ||
151 | printf("\t"); | ||
152 | crc = n << 8; | ||
153 | for (i = 0; i < 8; i++) { | ||
154 | if (crc & 0x8000U) | ||
155 | crc = (crc << 1) ^ poly; | ||
156 | else | ||
157 | crc <<= 1; | ||
158 | crc &= 0xFFFFU; | ||
159 | } | ||
160 | if (n == 255) | ||
161 | printf("0x%04xU ", crc); | ||
162 | else | ||
163 | printf("0x%04xU, ", crc); | ||
164 | if (n % 8 == 7) | ||
165 | printf("\n"); | ||
166 | } | ||
167 | printf("};\n"); | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | #endif /* defined(GENERATE) */ | ||
diff --git a/fs/udf/dir.c b/fs/udf/dir.c index 8d8643ada199..62dc270c69d1 100644 --- a/fs/udf/dir.c +++ b/fs/udf/dir.c | |||
@@ -39,13 +39,13 @@ | |||
39 | static int do_udf_readdir(struct inode *dir, struct file *filp, | 39 | static int do_udf_readdir(struct inode *dir, struct file *filp, |
40 | filldir_t filldir, void *dirent) | 40 | filldir_t filldir, void *dirent) |
41 | { | 41 | { |
42 | struct udf_fileident_bh fibh; | 42 | struct udf_fileident_bh fibh = { .sbh = NULL, .ebh = NULL}; |
43 | struct fileIdentDesc *fi = NULL; | 43 | struct fileIdentDesc *fi = NULL; |
44 | struct fileIdentDesc cfi; | 44 | struct fileIdentDesc cfi; |
45 | int block, iblock; | 45 | int block, iblock; |
46 | loff_t nf_pos = (filp->f_pos - 1) << 2; | 46 | loff_t nf_pos = (filp->f_pos - 1) << 2; |
47 | int flen; | 47 | int flen; |
48 | char fname[UDF_NAME_LEN]; | 48 | char *fname = NULL; |
49 | char *nameptr; | 49 | char *nameptr; |
50 | uint16_t liu; | 50 | uint16_t liu; |
51 | uint8_t lfi; | 51 | uint8_t lfi; |
@@ -54,23 +54,32 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, | |||
54 | kernel_lb_addr eloc; | 54 | kernel_lb_addr eloc; |
55 | uint32_t elen; | 55 | uint32_t elen; |
56 | sector_t offset; | 56 | sector_t offset; |
57 | int i, num; | 57 | int i, num, ret = 0; |
58 | unsigned int dt_type; | 58 | unsigned int dt_type; |
59 | struct extent_position epos = { NULL, 0, {0, 0} }; | 59 | struct extent_position epos = { NULL, 0, {0, 0} }; |
60 | struct udf_inode_info *iinfo; | 60 | struct udf_inode_info *iinfo; |
61 | 61 | ||
62 | if (nf_pos >= size) | 62 | if (nf_pos >= size) |
63 | return 0; | 63 | goto out; |
64 | |||
65 | fname = kmalloc(UDF_NAME_LEN, GFP_NOFS); | ||
66 | if (!fname) { | ||
67 | ret = -ENOMEM; | ||
68 | goto out; | ||
69 | } | ||
64 | 70 | ||
65 | if (nf_pos == 0) | 71 | if (nf_pos == 0) |
66 | nf_pos = udf_ext0_offset(dir); | 72 | nf_pos = udf_ext0_offset(dir); |
67 | 73 | ||
68 | fibh.soffset = fibh.eoffset = nf_pos & (dir->i_sb->s_blocksize - 1); | 74 | fibh.soffset = fibh.eoffset = nf_pos & (dir->i_sb->s_blocksize - 1); |
69 | iinfo = UDF_I(dir); | 75 | iinfo = UDF_I(dir); |
70 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { | 76 | if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { |
71 | fibh.sbh = fibh.ebh = NULL; | 77 | if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits, |
72 | } else if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits, | 78 | &epos, &eloc, &elen, &offset) |
73 | &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) { | 79 | != (EXT_RECORDED_ALLOCATED >> 30)) { |
80 | ret = -ENOENT; | ||
81 | goto out; | ||
82 | } | ||
74 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); | 83 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); |
75 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { | 84 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { |
76 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) | 85 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) |
@@ -83,8 +92,8 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, | |||
83 | } | 92 | } |
84 | 93 | ||
85 | if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) { | 94 | if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) { |
86 | brelse(epos.bh); | 95 | ret = -EIO; |
87 | return -EIO; | 96 | goto out; |
88 | } | 97 | } |
89 | 98 | ||
90 | if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) { | 99 | if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) { |
@@ -105,9 +114,6 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, | |||
105 | brelse(bha[i]); | 114 | brelse(bha[i]); |
106 | } | 115 | } |
107 | } | 116 | } |
108 | } else { | ||
109 | brelse(epos.bh); | ||
110 | return -ENOENT; | ||
111 | } | 117 | } |
112 | 118 | ||
113 | while (nf_pos < size) { | 119 | while (nf_pos < size) { |
@@ -115,13 +121,8 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, | |||
115 | 121 | ||
116 | fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc, | 122 | fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc, |
117 | &elen, &offset); | 123 | &elen, &offset); |
118 | if (!fi) { | 124 | if (!fi) |
119 | if (fibh.sbh != fibh.ebh) | 125 | goto out; |
120 | brelse(fibh.ebh); | ||
121 | brelse(fibh.sbh); | ||
122 | brelse(epos.bh); | ||
123 | return 0; | ||
124 | } | ||
125 | 126 | ||
126 | liu = le16_to_cpu(cfi.lengthOfImpUse); | 127 | liu = le16_to_cpu(cfi.lengthOfImpUse); |
127 | lfi = cfi.lengthFileIdent; | 128 | lfi = cfi.lengthFileIdent; |
@@ -167,53 +168,23 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, | |||
167 | dt_type = DT_UNKNOWN; | 168 | dt_type = DT_UNKNOWN; |
168 | } | 169 | } |
169 | 170 | ||
170 | if (flen) { | 171 | if (flen && filldir(dirent, fname, flen, filp->f_pos, |
171 | if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0) { | 172 | iblock, dt_type) < 0) |
172 | if (fibh.sbh != fibh.ebh) | 173 | goto out; |
173 | brelse(fibh.ebh); | ||
174 | brelse(fibh.sbh); | ||
175 | brelse(epos.bh); | ||
176 | return 0; | ||
177 | } | ||
178 | } | ||
179 | } /* end while */ | 174 | } /* end while */ |
180 | 175 | ||
181 | filp->f_pos = (nf_pos >> 2) + 1; | 176 | filp->f_pos = (nf_pos >> 2) + 1; |
182 | 177 | ||
178 | out: | ||
183 | if (fibh.sbh != fibh.ebh) | 179 | if (fibh.sbh != fibh.ebh) |
184 | brelse(fibh.ebh); | 180 | brelse(fibh.ebh); |
185 | brelse(fibh.sbh); | 181 | brelse(fibh.sbh); |
186 | brelse(epos.bh); | 182 | brelse(epos.bh); |
183 | kfree(fname); | ||
187 | 184 | ||
188 | return 0; | 185 | return ret; |
189 | } | 186 | } |
190 | 187 | ||
191 | /* | ||
192 | * udf_readdir | ||
193 | * | ||
194 | * PURPOSE | ||
195 | * Read a directory entry. | ||
196 | * | ||
197 | * DESCRIPTION | ||
198 | * Optional - sys_getdents() will return -ENOTDIR if this routine is not | ||
199 | * available. | ||
200 | * | ||
201 | * Refer to sys_getdents() in fs/readdir.c | ||
202 | * sys_getdents() -> . | ||
203 | * | ||
204 | * PRE-CONDITIONS | ||
205 | * filp Pointer to directory file. | ||
206 | * buf Pointer to directory entry buffer. | ||
207 | * filldir Pointer to filldir function. | ||
208 | * | ||
209 | * POST-CONDITIONS | ||
210 | * <return> >=0 on success. | ||
211 | * | ||
212 | * HISTORY | ||
213 | * July 1, 1997 - Andrew E. Mileski | ||
214 | * Written, tested, and released. | ||
215 | */ | ||
216 | |||
217 | static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir) | 188 | static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir) |
218 | { | 189 | { |
219 | struct inode *dir = filp->f_path.dentry->d_inode; | 190 | struct inode *dir = filp->f_path.dentry->d_inode; |
diff --git a/fs/udf/ecma_167.h b/fs/udf/ecma_167.h index 56387711589b..a0974df82b31 100644 --- a/fs/udf/ecma_167.h +++ b/fs/udf/ecma_167.h | |||
@@ -70,19 +70,6 @@ typedef struct { | |||
70 | uint8_t microseconds; | 70 | uint8_t microseconds; |
71 | } __attribute__ ((packed)) timestamp; | 71 | } __attribute__ ((packed)) timestamp; |
72 | 72 | ||
73 | typedef struct { | ||
74 | uint16_t typeAndTimezone; | ||
75 | int16_t year; | ||
76 | uint8_t month; | ||
77 | uint8_t day; | ||
78 | uint8_t hour; | ||
79 | uint8_t minute; | ||
80 | uint8_t second; | ||
81 | uint8_t centiseconds; | ||
82 | uint8_t hundredsOfMicroseconds; | ||
83 | uint8_t microseconds; | ||
84 | } __attribute__ ((packed)) kernel_timestamp; | ||
85 | |||
86 | /* Type and Time Zone (ECMA 167r3 1/7.3.1) */ | 73 | /* Type and Time Zone (ECMA 167r3 1/7.3.1) */ |
87 | #define TIMESTAMP_TYPE_MASK 0xF000 | 74 | #define TIMESTAMP_TYPE_MASK 0xF000 |
88 | #define TIMESTAMP_TYPE_CUT 0x0000 | 75 | #define TIMESTAMP_TYPE_CUT 0x0000 |
diff --git a/fs/udf/file.c b/fs/udf/file.c index 97c71ae7c689..0ed6e146a0d9 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c | |||
@@ -27,7 +27,6 @@ | |||
27 | 27 | ||
28 | #include "udfdecl.h" | 28 | #include "udfdecl.h" |
29 | #include <linux/fs.h> | 29 | #include <linux/fs.h> |
30 | #include <linux/udf_fs.h> | ||
31 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
32 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
33 | #include <linux/string.h> /* memset */ | 32 | #include <linux/string.h> /* memset */ |
@@ -144,40 +143,6 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
144 | return retval; | 143 | return retval; |
145 | } | 144 | } |
146 | 145 | ||
147 | /* | ||
148 | * udf_ioctl | ||
149 | * | ||
150 | * PURPOSE | ||
151 | * Issue an ioctl. | ||
152 | * | ||
153 | * DESCRIPTION | ||
154 | * Optional - sys_ioctl() will return -ENOTTY if this routine is not | ||
155 | * available, and the ioctl cannot be handled without filesystem help. | ||
156 | * | ||
157 | * sys_ioctl() handles these ioctls that apply only to regular files: | ||
158 | * FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD | ||
159 | * These ioctls are also handled by sys_ioctl(): | ||
160 | * FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC | ||
161 | * All other ioctls are passed to the filesystem. | ||
162 | * | ||
163 | * Refer to sys_ioctl() in fs/ioctl.c | ||
164 | * sys_ioctl() -> . | ||
165 | * | ||
166 | * PRE-CONDITIONS | ||
167 | * inode Pointer to inode that ioctl was issued on. | ||
168 | * filp Pointer to file that ioctl was issued on. | ||
169 | * cmd The ioctl command. | ||
170 | * arg The ioctl argument [can be interpreted as a | ||
171 | * user-space pointer if desired]. | ||
172 | * | ||
173 | * POST-CONDITIONS | ||
174 | * <return> Success (>=0) or an error code (<=0) that | ||
175 | * sys_ioctl() will return. | ||
176 | * | ||
177 | * HISTORY | ||
178 | * July 1, 1997 - Andrew E. Mileski | ||
179 | * Written, tested, and released. | ||
180 | */ | ||
181 | int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | 146 | int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, |
182 | unsigned long arg) | 147 | unsigned long arg) |
183 | { | 148 | { |
@@ -225,18 +190,6 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
225 | return result; | 190 | return result; |
226 | } | 191 | } |
227 | 192 | ||
228 | /* | ||
229 | * udf_release_file | ||
230 | * | ||
231 | * PURPOSE | ||
232 | * Called when all references to the file are closed | ||
233 | * | ||
234 | * DESCRIPTION | ||
235 | * Discard prealloced blocks | ||
236 | * | ||
237 | * HISTORY | ||
238 | * | ||
239 | */ | ||
240 | static int udf_release_file(struct inode *inode, struct file *filp) | 193 | static int udf_release_file(struct inode *inode, struct file *filp) |
241 | { | 194 | { |
242 | if (filp->f_mode & FMODE_WRITE) { | 195 | if (filp->f_mode & FMODE_WRITE) { |
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c index 84360315aca2..eb9cfa23dc3d 100644 --- a/fs/udf/ialloc.c +++ b/fs/udf/ialloc.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include "udfdecl.h" | 21 | #include "udfdecl.h" |
22 | #include <linux/fs.h> | 22 | #include <linux/fs.h> |
23 | #include <linux/quotaops.h> | 23 | #include <linux/quotaops.h> |
24 | #include <linux/udf_fs.h> | ||
25 | #include <linux/sched.h> | 24 | #include <linux/sched.h> |
26 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
27 | 26 | ||
@@ -47,11 +46,9 @@ void udf_free_inode(struct inode *inode) | |||
47 | struct logicalVolIntegrityDescImpUse *lvidiu = | 46 | struct logicalVolIntegrityDescImpUse *lvidiu = |
48 | udf_sb_lvidiu(sbi); | 47 | udf_sb_lvidiu(sbi); |
49 | if (S_ISDIR(inode->i_mode)) | 48 | if (S_ISDIR(inode->i_mode)) |
50 | lvidiu->numDirs = | 49 | le32_add_cpu(&lvidiu->numDirs, -1); |
51 | cpu_to_le32(le32_to_cpu(lvidiu->numDirs) - 1); | ||
52 | else | 50 | else |
53 | lvidiu->numFiles = | 51 | le32_add_cpu(&lvidiu->numFiles, -1); |
54 | cpu_to_le32(le32_to_cpu(lvidiu->numFiles) - 1); | ||
55 | 52 | ||
56 | mark_buffer_dirty(sbi->s_lvid_bh); | 53 | mark_buffer_dirty(sbi->s_lvid_bh); |
57 | } | 54 | } |
@@ -105,11 +102,9 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err) | |||
105 | lvhd = (struct logicalVolHeaderDesc *) | 102 | lvhd = (struct logicalVolHeaderDesc *) |
106 | (lvid->logicalVolContentsUse); | 103 | (lvid->logicalVolContentsUse); |
107 | if (S_ISDIR(mode)) | 104 | if (S_ISDIR(mode)) |
108 | lvidiu->numDirs = | 105 | le32_add_cpu(&lvidiu->numDirs, 1); |
109 | cpu_to_le32(le32_to_cpu(lvidiu->numDirs) + 1); | ||
110 | else | 106 | else |
111 | lvidiu->numFiles = | 107 | le32_add_cpu(&lvidiu->numFiles, 1); |
112 | cpu_to_le32(le32_to_cpu(lvidiu->numFiles) + 1); | ||
113 | iinfo->i_unique = uniqueID = le64_to_cpu(lvhd->uniqueID); | 108 | iinfo->i_unique = uniqueID = le64_to_cpu(lvhd->uniqueID); |
114 | if (!(++uniqueID & 0x00000000FFFFFFFFUL)) | 109 | if (!(++uniqueID & 0x00000000FFFFFFFFUL)) |
115 | uniqueID += 16; | 110 | uniqueID += 16; |
diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 24cfa55d0fdc..6e74b117aaf0 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/buffer_head.h> | 37 | #include <linux/buffer_head.h> |
38 | #include <linux/writeback.h> | 38 | #include <linux/writeback.h> |
39 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
40 | #include <linux/crc-itu-t.h> | ||
40 | 41 | ||
41 | #include "udf_i.h" | 42 | #include "udf_i.h" |
42 | #include "udf_sb.h" | 43 | #include "udf_sb.h" |
@@ -66,22 +67,7 @@ static void udf_update_extents(struct inode *, | |||
66 | struct extent_position *); | 67 | struct extent_position *); |
67 | static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); | 68 | static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); |
68 | 69 | ||
69 | /* | 70 | |
70 | * udf_delete_inode | ||
71 | * | ||
72 | * PURPOSE | ||
73 | * Clean-up before the specified inode is destroyed. | ||
74 | * | ||
75 | * DESCRIPTION | ||
76 | * This routine is called when the kernel destroys an inode structure | ||
77 | * ie. when iput() finds i_count == 0. | ||
78 | * | ||
79 | * HISTORY | ||
80 | * July 1, 1997 - Andrew E. Mileski | ||
81 | * Written, tested, and released. | ||
82 | * | ||
83 | * Called at the last iput() if i_nlink is zero. | ||
84 | */ | ||
85 | void udf_delete_inode(struct inode *inode) | 71 | void udf_delete_inode(struct inode *inode) |
86 | { | 72 | { |
87 | truncate_inode_pages(&inode->i_data, 0); | 73 | truncate_inode_pages(&inode->i_data, 0); |
@@ -323,9 +309,6 @@ static int udf_get_block(struct inode *inode, sector_t block, | |||
323 | 309 | ||
324 | lock_kernel(); | 310 | lock_kernel(); |
325 | 311 | ||
326 | if (block < 0) | ||
327 | goto abort_negative; | ||
328 | |||
329 | iinfo = UDF_I(inode); | 312 | iinfo = UDF_I(inode); |
330 | if (block == iinfo->i_next_alloc_block + 1) { | 313 | if (block == iinfo->i_next_alloc_block + 1) { |
331 | iinfo->i_next_alloc_block++; | 314 | iinfo->i_next_alloc_block++; |
@@ -347,10 +330,6 @@ static int udf_get_block(struct inode *inode, sector_t block, | |||
347 | abort: | 330 | abort: |
348 | unlock_kernel(); | 331 | unlock_kernel(); |
349 | return err; | 332 | return err; |
350 | |||
351 | abort_negative: | ||
352 | udf_warning(inode->i_sb, "udf_get_block", "block < 0"); | ||
353 | goto abort; | ||
354 | } | 333 | } |
355 | 334 | ||
356 | static struct buffer_head *udf_getblk(struct inode *inode, long block, | 335 | static struct buffer_head *udf_getblk(struct inode *inode, long block, |
@@ -1116,42 +1095,36 @@ static void __udf_read_inode(struct inode *inode) | |||
1116 | fe = (struct fileEntry *)bh->b_data; | 1095 | fe = (struct fileEntry *)bh->b_data; |
1117 | 1096 | ||
1118 | if (fe->icbTag.strategyType == cpu_to_le16(4096)) { | 1097 | if (fe->icbTag.strategyType == cpu_to_le16(4096)) { |
1119 | struct buffer_head *ibh = NULL, *nbh = NULL; | 1098 | struct buffer_head *ibh; |
1120 | struct indirectEntry *ie; | ||
1121 | 1099 | ||
1122 | ibh = udf_read_ptagged(inode->i_sb, iinfo->i_location, 1, | 1100 | ibh = udf_read_ptagged(inode->i_sb, iinfo->i_location, 1, |
1123 | &ident); | 1101 | &ident); |
1124 | if (ident == TAG_IDENT_IE) { | 1102 | if (ident == TAG_IDENT_IE && ibh) { |
1125 | if (ibh) { | 1103 | struct buffer_head *nbh = NULL; |
1126 | kernel_lb_addr loc; | 1104 | kernel_lb_addr loc; |
1127 | ie = (struct indirectEntry *)ibh->b_data; | 1105 | struct indirectEntry *ie; |
1128 | 1106 | ||
1129 | loc = lelb_to_cpu(ie->indirectICB.extLocation); | 1107 | ie = (struct indirectEntry *)ibh->b_data; |
1130 | 1108 | loc = lelb_to_cpu(ie->indirectICB.extLocation); | |
1131 | if (ie->indirectICB.extLength && | 1109 | |
1132 | (nbh = udf_read_ptagged(inode->i_sb, loc, 0, | 1110 | if (ie->indirectICB.extLength && |
1133 | &ident))) { | 1111 | (nbh = udf_read_ptagged(inode->i_sb, loc, 0, |
1134 | if (ident == TAG_IDENT_FE || | 1112 | &ident))) { |
1135 | ident == TAG_IDENT_EFE) { | 1113 | if (ident == TAG_IDENT_FE || |
1136 | memcpy(&iinfo->i_location, | 1114 | ident == TAG_IDENT_EFE) { |
1137 | &loc, | 1115 | memcpy(&iinfo->i_location, |
1138 | sizeof(kernel_lb_addr)); | 1116 | &loc, |
1139 | brelse(bh); | 1117 | sizeof(kernel_lb_addr)); |
1140 | brelse(ibh); | 1118 | brelse(bh); |
1141 | brelse(nbh); | ||
1142 | __udf_read_inode(inode); | ||
1143 | return; | ||
1144 | } else { | ||
1145 | brelse(nbh); | ||
1146 | brelse(ibh); | ||
1147 | } | ||
1148 | } else { | ||
1149 | brelse(ibh); | 1119 | brelse(ibh); |
1120 | brelse(nbh); | ||
1121 | __udf_read_inode(inode); | ||
1122 | return; | ||
1150 | } | 1123 | } |
1124 | brelse(nbh); | ||
1151 | } | 1125 | } |
1152 | } else { | ||
1153 | brelse(ibh); | ||
1154 | } | 1126 | } |
1127 | brelse(ibh); | ||
1155 | } else if (fe->icbTag.strategyType != cpu_to_le16(4)) { | 1128 | } else if (fe->icbTag.strategyType != cpu_to_le16(4)) { |
1156 | printk(KERN_ERR "udf: unsupported strategy type: %d\n", | 1129 | printk(KERN_ERR "udf: unsupported strategy type: %d\n", |
1157 | le16_to_cpu(fe->icbTag.strategyType)); | 1130 | le16_to_cpu(fe->icbTag.strategyType)); |
@@ -1168,8 +1141,6 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) | |||
1168 | { | 1141 | { |
1169 | struct fileEntry *fe; | 1142 | struct fileEntry *fe; |
1170 | struct extendedFileEntry *efe; | 1143 | struct extendedFileEntry *efe; |
1171 | time_t convtime; | ||
1172 | long convtime_usec; | ||
1173 | int offset; | 1144 | int offset; |
1174 | struct udf_sb_info *sbi = UDF_SB(inode->i_sb); | 1145 | struct udf_sb_info *sbi = UDF_SB(inode->i_sb); |
1175 | struct udf_inode_info *iinfo = UDF_I(inode); | 1146 | struct udf_inode_info *iinfo = UDF_I(inode); |
@@ -1257,29 +1228,15 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) | |||
1257 | inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) << | 1228 | inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) << |
1258 | (inode->i_sb->s_blocksize_bits - 9); | 1229 | (inode->i_sb->s_blocksize_bits - 9); |
1259 | 1230 | ||
1260 | if (udf_stamp_to_time(&convtime, &convtime_usec, | 1231 | if (!udf_disk_stamp_to_time(&inode->i_atime, fe->accessTime)) |
1261 | lets_to_cpu(fe->accessTime))) { | ||
1262 | inode->i_atime.tv_sec = convtime; | ||
1263 | inode->i_atime.tv_nsec = convtime_usec * 1000; | ||
1264 | } else { | ||
1265 | inode->i_atime = sbi->s_record_time; | 1232 | inode->i_atime = sbi->s_record_time; |
1266 | } | ||
1267 | 1233 | ||
1268 | if (udf_stamp_to_time(&convtime, &convtime_usec, | 1234 | if (!udf_disk_stamp_to_time(&inode->i_mtime, |
1269 | lets_to_cpu(fe->modificationTime))) { | 1235 | fe->modificationTime)) |
1270 | inode->i_mtime.tv_sec = convtime; | ||
1271 | inode->i_mtime.tv_nsec = convtime_usec * 1000; | ||
1272 | } else { | ||
1273 | inode->i_mtime = sbi->s_record_time; | 1236 | inode->i_mtime = sbi->s_record_time; |
1274 | } | ||
1275 | 1237 | ||
1276 | if (udf_stamp_to_time(&convtime, &convtime_usec, | 1238 | if (!udf_disk_stamp_to_time(&inode->i_ctime, fe->attrTime)) |
1277 | lets_to_cpu(fe->attrTime))) { | ||
1278 | inode->i_ctime.tv_sec = convtime; | ||
1279 | inode->i_ctime.tv_nsec = convtime_usec * 1000; | ||
1280 | } else { | ||
1281 | inode->i_ctime = sbi->s_record_time; | 1239 | inode->i_ctime = sbi->s_record_time; |
1282 | } | ||
1283 | 1240 | ||
1284 | iinfo->i_unique = le64_to_cpu(fe->uniqueID); | 1241 | iinfo->i_unique = le64_to_cpu(fe->uniqueID); |
1285 | iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr); | 1242 | iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr); |
@@ -1289,37 +1246,18 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) | |||
1289 | inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) << | 1246 | inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) << |
1290 | (inode->i_sb->s_blocksize_bits - 9); | 1247 | (inode->i_sb->s_blocksize_bits - 9); |
1291 | 1248 | ||
1292 | if (udf_stamp_to_time(&convtime, &convtime_usec, | 1249 | if (!udf_disk_stamp_to_time(&inode->i_atime, efe->accessTime)) |
1293 | lets_to_cpu(efe->accessTime))) { | ||
1294 | inode->i_atime.tv_sec = convtime; | ||
1295 | inode->i_atime.tv_nsec = convtime_usec * 1000; | ||
1296 | } else { | ||
1297 | inode->i_atime = sbi->s_record_time; | 1250 | inode->i_atime = sbi->s_record_time; |
1298 | } | ||
1299 | 1251 | ||
1300 | if (udf_stamp_to_time(&convtime, &convtime_usec, | 1252 | if (!udf_disk_stamp_to_time(&inode->i_mtime, |
1301 | lets_to_cpu(efe->modificationTime))) { | 1253 | efe->modificationTime)) |
1302 | inode->i_mtime.tv_sec = convtime; | ||
1303 | inode->i_mtime.tv_nsec = convtime_usec * 1000; | ||
1304 | } else { | ||
1305 | inode->i_mtime = sbi->s_record_time; | 1254 | inode->i_mtime = sbi->s_record_time; |
1306 | } | ||
1307 | 1255 | ||
1308 | if (udf_stamp_to_time(&convtime, &convtime_usec, | 1256 | if (!udf_disk_stamp_to_time(&iinfo->i_crtime, efe->createTime)) |
1309 | lets_to_cpu(efe->createTime))) { | ||
1310 | iinfo->i_crtime.tv_sec = convtime; | ||
1311 | iinfo->i_crtime.tv_nsec = convtime_usec * 1000; | ||
1312 | } else { | ||
1313 | iinfo->i_crtime = sbi->s_record_time; | 1257 | iinfo->i_crtime = sbi->s_record_time; |
1314 | } | ||
1315 | 1258 | ||
1316 | if (udf_stamp_to_time(&convtime, &convtime_usec, | 1259 | if (!udf_disk_stamp_to_time(&inode->i_ctime, efe->attrTime)) |
1317 | lets_to_cpu(efe->attrTime))) { | ||
1318 | inode->i_ctime.tv_sec = convtime; | ||
1319 | inode->i_ctime.tv_nsec = convtime_usec * 1000; | ||
1320 | } else { | ||
1321 | inode->i_ctime = sbi->s_record_time; | 1260 | inode->i_ctime = sbi->s_record_time; |
1322 | } | ||
1323 | 1261 | ||
1324 | iinfo->i_unique = le64_to_cpu(efe->uniqueID); | 1262 | iinfo->i_unique = le64_to_cpu(efe->uniqueID); |
1325 | iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr); | 1263 | iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr); |
@@ -1338,6 +1276,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) | |||
1338 | case ICBTAG_FILE_TYPE_REALTIME: | 1276 | case ICBTAG_FILE_TYPE_REALTIME: |
1339 | case ICBTAG_FILE_TYPE_REGULAR: | 1277 | case ICBTAG_FILE_TYPE_REGULAR: |
1340 | case ICBTAG_FILE_TYPE_UNDEF: | 1278 | case ICBTAG_FILE_TYPE_UNDEF: |
1279 | case ICBTAG_FILE_TYPE_VAT20: | ||
1341 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) | 1280 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) |
1342 | inode->i_data.a_ops = &udf_adinicb_aops; | 1281 | inode->i_data.a_ops = &udf_adinicb_aops; |
1343 | else | 1282 | else |
@@ -1363,6 +1302,15 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) | |||
1363 | inode->i_op = &page_symlink_inode_operations; | 1302 | inode->i_op = &page_symlink_inode_operations; |
1364 | inode->i_mode = S_IFLNK | S_IRWXUGO; | 1303 | inode->i_mode = S_IFLNK | S_IRWXUGO; |
1365 | break; | 1304 | break; |
1305 | case ICBTAG_FILE_TYPE_MAIN: | ||
1306 | udf_debug("METADATA FILE-----\n"); | ||
1307 | break; | ||
1308 | case ICBTAG_FILE_TYPE_MIRROR: | ||
1309 | udf_debug("METADATA MIRROR FILE-----\n"); | ||
1310 | break; | ||
1311 | case ICBTAG_FILE_TYPE_BITMAP: | ||
1312 | udf_debug("METADATA BITMAP FILE-----\n"); | ||
1313 | break; | ||
1366 | default: | 1314 | default: |
1367 | printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown " | 1315 | printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown " |
1368 | "file type=%d\n", inode->i_ino, | 1316 | "file type=%d\n", inode->i_ino, |
@@ -1416,21 +1364,6 @@ static mode_t udf_convert_permissions(struct fileEntry *fe) | |||
1416 | return mode; | 1364 | return mode; |
1417 | } | 1365 | } |
1418 | 1366 | ||
1419 | /* | ||
1420 | * udf_write_inode | ||
1421 | * | ||
1422 | * PURPOSE | ||
1423 | * Write out the specified inode. | ||
1424 | * | ||
1425 | * DESCRIPTION | ||
1426 | * This routine is called whenever an inode is synced. | ||
1427 | * Currently this routine is just a placeholder. | ||
1428 | * | ||
1429 | * HISTORY | ||
1430 | * July 1, 1997 - Andrew E. Mileski | ||
1431 | * Written, tested, and released. | ||
1432 | */ | ||
1433 | |||
1434 | int udf_write_inode(struct inode *inode, int sync) | 1367 | int udf_write_inode(struct inode *inode, int sync) |
1435 | { | 1368 | { |
1436 | int ret; | 1369 | int ret; |
@@ -1455,7 +1388,6 @@ static int udf_update_inode(struct inode *inode, int do_sync) | |||
1455 | uint32_t udfperms; | 1388 | uint32_t udfperms; |
1456 | uint16_t icbflags; | 1389 | uint16_t icbflags; |
1457 | uint16_t crclen; | 1390 | uint16_t crclen; |
1458 | kernel_timestamp cpu_time; | ||
1459 | int err = 0; | 1391 | int err = 0; |
1460 | struct udf_sb_info *sbi = UDF_SB(inode->i_sb); | 1392 | struct udf_sb_info *sbi = UDF_SB(inode->i_sb); |
1461 | unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; | 1393 | unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; |
@@ -1488,9 +1420,9 @@ static int udf_update_inode(struct inode *inode, int do_sync) | |||
1488 | iinfo->i_location. | 1420 | iinfo->i_location. |
1489 | logicalBlockNum); | 1421 | logicalBlockNum); |
1490 | use->descTag.descCRCLength = cpu_to_le16(crclen); | 1422 | use->descTag.descCRCLength = cpu_to_le16(crclen); |
1491 | use->descTag.descCRC = cpu_to_le16(udf_crc((char *)use + | 1423 | use->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)use + |
1492 | sizeof(tag), crclen, | 1424 | sizeof(tag), |
1493 | 0)); | 1425 | crclen)); |
1494 | use->descTag.tagChecksum = udf_tag_checksum(&use->descTag); | 1426 | use->descTag.tagChecksum = udf_tag_checksum(&use->descTag); |
1495 | 1427 | ||
1496 | mark_buffer_dirty(bh); | 1428 | mark_buffer_dirty(bh); |
@@ -1558,12 +1490,9 @@ static int udf_update_inode(struct inode *inode, int do_sync) | |||
1558 | (inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >> | 1490 | (inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >> |
1559 | (blocksize_bits - 9)); | 1491 | (blocksize_bits - 9)); |
1560 | 1492 | ||
1561 | if (udf_time_to_stamp(&cpu_time, inode->i_atime)) | 1493 | udf_time_to_disk_stamp(&fe->accessTime, inode->i_atime); |
1562 | fe->accessTime = cpu_to_lets(cpu_time); | 1494 | udf_time_to_disk_stamp(&fe->modificationTime, inode->i_mtime); |
1563 | if (udf_time_to_stamp(&cpu_time, inode->i_mtime)) | 1495 | udf_time_to_disk_stamp(&fe->attrTime, inode->i_ctime); |
1564 | fe->modificationTime = cpu_to_lets(cpu_time); | ||
1565 | if (udf_time_to_stamp(&cpu_time, inode->i_ctime)) | ||
1566 | fe->attrTime = cpu_to_lets(cpu_time); | ||
1567 | memset(&(fe->impIdent), 0, sizeof(regid)); | 1496 | memset(&(fe->impIdent), 0, sizeof(regid)); |
1568 | strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER); | 1497 | strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER); |
1569 | fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; | 1498 | fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; |
@@ -1598,14 +1527,10 @@ static int udf_update_inode(struct inode *inode, int do_sync) | |||
1598 | iinfo->i_crtime.tv_nsec > inode->i_ctime.tv_nsec)) | 1527 | iinfo->i_crtime.tv_nsec > inode->i_ctime.tv_nsec)) |
1599 | iinfo->i_crtime = inode->i_ctime; | 1528 | iinfo->i_crtime = inode->i_ctime; |
1600 | 1529 | ||
1601 | if (udf_time_to_stamp(&cpu_time, inode->i_atime)) | 1530 | udf_time_to_disk_stamp(&efe->accessTime, inode->i_atime); |
1602 | efe->accessTime = cpu_to_lets(cpu_time); | 1531 | udf_time_to_disk_stamp(&efe->modificationTime, inode->i_mtime); |
1603 | if (udf_time_to_stamp(&cpu_time, inode->i_mtime)) | 1532 | udf_time_to_disk_stamp(&efe->createTime, iinfo->i_crtime); |
1604 | efe->modificationTime = cpu_to_lets(cpu_time); | 1533 | udf_time_to_disk_stamp(&efe->attrTime, inode->i_ctime); |
1605 | if (udf_time_to_stamp(&cpu_time, iinfo->i_crtime)) | ||
1606 | efe->createTime = cpu_to_lets(cpu_time); | ||
1607 | if (udf_time_to_stamp(&cpu_time, inode->i_ctime)) | ||
1608 | efe->attrTime = cpu_to_lets(cpu_time); | ||
1609 | 1534 | ||
1610 | memset(&(efe->impIdent), 0, sizeof(regid)); | 1535 | memset(&(efe->impIdent), 0, sizeof(regid)); |
1611 | strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER); | 1536 | strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER); |
@@ -1660,8 +1585,8 @@ static int udf_update_inode(struct inode *inode, int do_sync) | |||
1660 | crclen += iinfo->i_lenEAttr + iinfo->i_lenAlloc - | 1585 | crclen += iinfo->i_lenEAttr + iinfo->i_lenAlloc - |
1661 | sizeof(tag); | 1586 | sizeof(tag); |
1662 | fe->descTag.descCRCLength = cpu_to_le16(crclen); | 1587 | fe->descTag.descCRCLength = cpu_to_le16(crclen); |
1663 | fe->descTag.descCRC = cpu_to_le16(udf_crc((char *)fe + sizeof(tag), | 1588 | fe->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)fe + sizeof(tag), |
1664 | crclen, 0)); | 1589 | crclen)); |
1665 | fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag); | 1590 | fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag); |
1666 | 1591 | ||
1667 | /* write the data blocks */ | 1592 | /* write the data blocks */ |
@@ -1778,9 +1703,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, | |||
1778 | 1703 | ||
1779 | if (epos->bh) { | 1704 | if (epos->bh) { |
1780 | aed = (struct allocExtDesc *)epos->bh->b_data; | 1705 | aed = (struct allocExtDesc *)epos->bh->b_data; |
1781 | aed->lengthAllocDescs = | 1706 | le32_add_cpu(&aed->lengthAllocDescs, adsize); |
1782 | cpu_to_le32(le32_to_cpu( | ||
1783 | aed->lengthAllocDescs) + adsize); | ||
1784 | } else { | 1707 | } else { |
1785 | iinfo->i_lenAlloc += adsize; | 1708 | iinfo->i_lenAlloc += adsize; |
1786 | mark_inode_dirty(inode); | 1709 | mark_inode_dirty(inode); |
@@ -1830,9 +1753,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, | |||
1830 | mark_inode_dirty(inode); | 1753 | mark_inode_dirty(inode); |
1831 | } else { | 1754 | } else { |
1832 | aed = (struct allocExtDesc *)epos->bh->b_data; | 1755 | aed = (struct allocExtDesc *)epos->bh->b_data; |
1833 | aed->lengthAllocDescs = | 1756 | le32_add_cpu(&aed->lengthAllocDescs, adsize); |
1834 | cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + | ||
1835 | adsize); | ||
1836 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || | 1757 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || |
1837 | UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) | 1758 | UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) |
1838 | udf_update_tag(epos->bh->b_data, | 1759 | udf_update_tag(epos->bh->b_data, |
@@ -2046,9 +1967,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos, | |||
2046 | mark_inode_dirty(inode); | 1967 | mark_inode_dirty(inode); |
2047 | } else { | 1968 | } else { |
2048 | aed = (struct allocExtDesc *)oepos.bh->b_data; | 1969 | aed = (struct allocExtDesc *)oepos.bh->b_data; |
2049 | aed->lengthAllocDescs = | 1970 | le32_add_cpu(&aed->lengthAllocDescs, -(2 * adsize)); |
2050 | cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - | ||
2051 | (2 * adsize)); | ||
2052 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || | 1971 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || |
2053 | UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) | 1972 | UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) |
2054 | udf_update_tag(oepos.bh->b_data, | 1973 | udf_update_tag(oepos.bh->b_data, |
@@ -2065,9 +1984,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos, | |||
2065 | mark_inode_dirty(inode); | 1984 | mark_inode_dirty(inode); |
2066 | } else { | 1985 | } else { |
2067 | aed = (struct allocExtDesc *)oepos.bh->b_data; | 1986 | aed = (struct allocExtDesc *)oepos.bh->b_data; |
2068 | aed->lengthAllocDescs = | 1987 | le32_add_cpu(&aed->lengthAllocDescs, -adsize); |
2069 | cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - | ||
2070 | adsize); | ||
2071 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || | 1988 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || |
2072 | UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) | 1989 | UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) |
2073 | udf_update_tag(oepos.bh->b_data, | 1990 | udf_update_tag(oepos.bh->b_data, |
@@ -2095,11 +2012,6 @@ int8_t inode_bmap(struct inode *inode, sector_t block, | |||
2095 | int8_t etype; | 2012 | int8_t etype; |
2096 | struct udf_inode_info *iinfo; | 2013 | struct udf_inode_info *iinfo; |
2097 | 2014 | ||
2098 | if (block < 0) { | ||
2099 | printk(KERN_ERR "udf: inode_bmap: block < 0\n"); | ||
2100 | return -1; | ||
2101 | } | ||
2102 | |||
2103 | iinfo = UDF_I(inode); | 2015 | iinfo = UDF_I(inode); |
2104 | pos->offset = 0; | 2016 | pos->offset = 0; |
2105 | pos->block = iinfo->i_location; | 2017 | pos->block = iinfo->i_location; |
diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c index 579bae71e67e..703843f30ffd 100644 --- a/fs/udf/lowlevel.c +++ b/fs/udf/lowlevel.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/cdrom.h> | 23 | #include <linux/cdrom.h> |
24 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
25 | 25 | ||
26 | #include <linux/udf_fs.h> | ||
27 | #include "udf_sb.h" | 26 | #include "udf_sb.h" |
28 | 27 | ||
29 | unsigned int udf_get_last_session(struct super_block *sb) | 28 | unsigned int udf_get_last_session(struct super_block *sb) |
diff --git a/fs/udf/misc.c b/fs/udf/misc.c index a1d6da0caf71..84bf0fd4a4f1 100644 --- a/fs/udf/misc.c +++ b/fs/udf/misc.c | |||
@@ -23,8 +23,8 @@ | |||
23 | 23 | ||
24 | #include <linux/fs.h> | 24 | #include <linux/fs.h> |
25 | #include <linux/string.h> | 25 | #include <linux/string.h> |
26 | #include <linux/udf_fs.h> | ||
27 | #include <linux/buffer_head.h> | 26 | #include <linux/buffer_head.h> |
27 | #include <linux/crc-itu-t.h> | ||
28 | 28 | ||
29 | #include "udf_i.h" | 29 | #include "udf_i.h" |
30 | #include "udf_sb.h" | 30 | #include "udf_sb.h" |
@@ -136,8 +136,8 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size, | |||
136 | /* rewrite CRC + checksum of eahd */ | 136 | /* rewrite CRC + checksum of eahd */ |
137 | crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag); | 137 | crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag); |
138 | eahd->descTag.descCRCLength = cpu_to_le16(crclen); | 138 | eahd->descTag.descCRCLength = cpu_to_le16(crclen); |
139 | eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd + | 139 | eahd->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)eahd + |
140 | sizeof(tag), crclen, 0)); | 140 | sizeof(tag), crclen)); |
141 | eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag); | 141 | eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag); |
142 | iinfo->i_lenEAttr += size; | 142 | iinfo->i_lenEAttr += size; |
143 | return (struct genericFormat *)&ea[offset]; | 143 | return (struct genericFormat *)&ea[offset]; |
@@ -204,16 +204,15 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, | |||
204 | { | 204 | { |
205 | tag *tag_p; | 205 | tag *tag_p; |
206 | struct buffer_head *bh = NULL; | 206 | struct buffer_head *bh = NULL; |
207 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
208 | 207 | ||
209 | /* Read the block */ | 208 | /* Read the block */ |
210 | if (block == 0xFFFFFFFF) | 209 | if (block == 0xFFFFFFFF) |
211 | return NULL; | 210 | return NULL; |
212 | 211 | ||
213 | bh = udf_tread(sb, block + sbi->s_session); | 212 | bh = udf_tread(sb, block); |
214 | if (!bh) { | 213 | if (!bh) { |
215 | udf_debug("block=%d, location=%d: read failed\n", | 214 | udf_debug("block=%d, location=%d: read failed\n", |
216 | block + sbi->s_session, location); | 215 | block, location); |
217 | return NULL; | 216 | return NULL; |
218 | } | 217 | } |
219 | 218 | ||
@@ -223,8 +222,7 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, | |||
223 | 222 | ||
224 | if (location != le32_to_cpu(tag_p->tagLocation)) { | 223 | if (location != le32_to_cpu(tag_p->tagLocation)) { |
225 | udf_debug("location mismatch block %u, tag %u != %u\n", | 224 | udf_debug("location mismatch block %u, tag %u != %u\n", |
226 | block + sbi->s_session, | 225 | block, le32_to_cpu(tag_p->tagLocation), location); |
227 | le32_to_cpu(tag_p->tagLocation), location); | ||
228 | goto error_out; | 226 | goto error_out; |
229 | } | 227 | } |
230 | 228 | ||
@@ -244,13 +242,13 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, | |||
244 | 242 | ||
245 | /* Verify the descriptor CRC */ | 243 | /* Verify the descriptor CRC */ |
246 | if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize || | 244 | if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize || |
247 | le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag), | 245 | le16_to_cpu(tag_p->descCRC) == crc_itu_t(0, |
248 | le16_to_cpu(tag_p->descCRCLength), 0)) | 246 | bh->b_data + sizeof(tag), |
247 | le16_to_cpu(tag_p->descCRCLength))) | ||
249 | return bh; | 248 | return bh; |
250 | 249 | ||
251 | udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", | 250 | udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", block, |
252 | block + sbi->s_session, le16_to_cpu(tag_p->descCRC), | 251 | le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength)); |
253 | le16_to_cpu(tag_p->descCRCLength)); | ||
254 | 252 | ||
255 | error_out: | 253 | error_out: |
256 | brelse(bh); | 254 | brelse(bh); |
@@ -270,7 +268,7 @@ void udf_update_tag(char *data, int length) | |||
270 | length -= sizeof(tag); | 268 | length -= sizeof(tag); |
271 | 269 | ||
272 | tptr->descCRCLength = cpu_to_le16(length); | 270 | tptr->descCRCLength = cpu_to_le16(length); |
273 | tptr->descCRC = cpu_to_le16(udf_crc(data + sizeof(tag), length, 0)); | 271 | tptr->descCRC = cpu_to_le16(crc_itu_t(0, data + sizeof(tag), length)); |
274 | tptr->tagChecksum = udf_tag_checksum(tptr); | 272 | tptr->tagChecksum = udf_tag_checksum(tptr); |
275 | } | 273 | } |
276 | 274 | ||
diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 112a5fb0b27b..ba5537d4bc15 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/smp_lock.h> | 31 | #include <linux/smp_lock.h> |
32 | #include <linux/buffer_head.h> | 32 | #include <linux/buffer_head.h> |
33 | #include <linux/sched.h> | 33 | #include <linux/sched.h> |
34 | #include <linux/crc-itu-t.h> | ||
34 | 35 | ||
35 | static inline int udf_match(int len1, const char *name1, int len2, | 36 | static inline int udf_match(int len1, const char *name1, int len2, |
36 | const char *name2) | 37 | const char *name2) |
@@ -97,25 +98,23 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi, | |||
97 | memset(fibh->ebh->b_data, 0x00, padlen + offset); | 98 | memset(fibh->ebh->b_data, 0x00, padlen + offset); |
98 | } | 99 | } |
99 | 100 | ||
100 | crc = udf_crc((uint8_t *)cfi + sizeof(tag), | 101 | crc = crc_itu_t(0, (uint8_t *)cfi + sizeof(tag), |
101 | sizeof(struct fileIdentDesc) - sizeof(tag), 0); | 102 | sizeof(struct fileIdentDesc) - sizeof(tag)); |
102 | 103 | ||
103 | if (fibh->sbh == fibh->ebh) { | 104 | if (fibh->sbh == fibh->ebh) { |
104 | crc = udf_crc((uint8_t *)sfi->impUse, | 105 | crc = crc_itu_t(crc, (uint8_t *)sfi->impUse, |
105 | crclen + sizeof(tag) - | 106 | crclen + sizeof(tag) - |
106 | sizeof(struct fileIdentDesc), crc); | 107 | sizeof(struct fileIdentDesc)); |
107 | } else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) { | 108 | } else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) { |
108 | crc = udf_crc(fibh->ebh->b_data + | 109 | crc = crc_itu_t(crc, fibh->ebh->b_data + |
109 | sizeof(struct fileIdentDesc) + | 110 | sizeof(struct fileIdentDesc) + |
110 | fibh->soffset, | 111 | fibh->soffset, |
111 | crclen + sizeof(tag) - | 112 | crclen + sizeof(tag) - |
112 | sizeof(struct fileIdentDesc), | 113 | sizeof(struct fileIdentDesc)); |
113 | crc); | ||
114 | } else { | 114 | } else { |
115 | crc = udf_crc((uint8_t *)sfi->impUse, | 115 | crc = crc_itu_t(crc, (uint8_t *)sfi->impUse, |
116 | -fibh->soffset - sizeof(struct fileIdentDesc), | 116 | -fibh->soffset - sizeof(struct fileIdentDesc)); |
117 | crc); | 117 | crc = crc_itu_t(crc, fibh->ebh->b_data, fibh->eoffset); |
118 | crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc); | ||
119 | } | 118 | } |
120 | 119 | ||
121 | cfi->descTag.descCRC = cpu_to_le16(crc); | 120 | cfi->descTag.descCRC = cpu_to_le16(crc); |
@@ -149,7 +148,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, | |||
149 | struct fileIdentDesc *fi = NULL; | 148 | struct fileIdentDesc *fi = NULL; |
150 | loff_t f_pos; | 149 | loff_t f_pos; |
151 | int block, flen; | 150 | int block, flen; |
152 | char fname[UDF_NAME_LEN]; | 151 | char *fname = NULL; |
153 | char *nameptr; | 152 | char *nameptr; |
154 | uint8_t lfi; | 153 | uint8_t lfi; |
155 | uint16_t liu; | 154 | uint16_t liu; |
@@ -163,12 +162,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, | |||
163 | size = udf_ext0_offset(dir) + dir->i_size; | 162 | size = udf_ext0_offset(dir) + dir->i_size; |
164 | f_pos = udf_ext0_offset(dir); | 163 | f_pos = udf_ext0_offset(dir); |
165 | 164 | ||
165 | fibh->sbh = fibh->ebh = NULL; | ||
166 | fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); | 166 | fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); |
167 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) | 167 | if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { |
168 | fibh->sbh = fibh->ebh = NULL; | 168 | if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos, |
169 | else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, | 169 | &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) |
170 | &epos, &eloc, &elen, &offset) == | 170 | goto out_err; |
171 | (EXT_RECORDED_ALLOCATED >> 30)) { | ||
172 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); | 171 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); |
173 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { | 172 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { |
174 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) | 173 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) |
@@ -179,25 +178,19 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, | |||
179 | offset = 0; | 178 | offset = 0; |
180 | 179 | ||
181 | fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); | 180 | fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); |
182 | if (!fibh->sbh) { | 181 | if (!fibh->sbh) |
183 | brelse(epos.bh); | 182 | goto out_err; |
184 | return NULL; | ||
185 | } | ||
186 | } else { | ||
187 | brelse(epos.bh); | ||
188 | return NULL; | ||
189 | } | 183 | } |
190 | 184 | ||
185 | fname = kmalloc(UDF_NAME_LEN, GFP_NOFS); | ||
186 | if (!fname) | ||
187 | goto out_err; | ||
188 | |||
191 | while (f_pos < size) { | 189 | while (f_pos < size) { |
192 | fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, | 190 | fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, |
193 | &elen, &offset); | 191 | &elen, &offset); |
194 | if (!fi) { | 192 | if (!fi) |
195 | if (fibh->sbh != fibh->ebh) | 193 | goto out_err; |
196 | brelse(fibh->ebh); | ||
197 | brelse(fibh->sbh); | ||
198 | brelse(epos.bh); | ||
199 | return NULL; | ||
200 | } | ||
201 | 194 | ||
202 | liu = le16_to_cpu(cfi->lengthOfImpUse); | 195 | liu = le16_to_cpu(cfi->lengthOfImpUse); |
203 | lfi = cfi->lengthFileIdent; | 196 | lfi = cfi->lengthFileIdent; |
@@ -237,53 +230,22 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, | |||
237 | 230 | ||
238 | flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); | 231 | flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); |
239 | if (flen && udf_match(flen, fname, dentry->d_name.len, | 232 | if (flen && udf_match(flen, fname, dentry->d_name.len, |
240 | dentry->d_name.name)) { | 233 | dentry->d_name.name)) |
241 | brelse(epos.bh); | 234 | goto out_ok; |
242 | return fi; | ||
243 | } | ||
244 | } | 235 | } |
245 | 236 | ||
237 | out_err: | ||
238 | fi = NULL; | ||
246 | if (fibh->sbh != fibh->ebh) | 239 | if (fibh->sbh != fibh->ebh) |
247 | brelse(fibh->ebh); | 240 | brelse(fibh->ebh); |
248 | brelse(fibh->sbh); | 241 | brelse(fibh->sbh); |
242 | out_ok: | ||
249 | brelse(epos.bh); | 243 | brelse(epos.bh); |
244 | kfree(fname); | ||
250 | 245 | ||
251 | return NULL; | 246 | return fi; |
252 | } | 247 | } |
253 | 248 | ||
254 | /* | ||
255 | * udf_lookup | ||
256 | * | ||
257 | * PURPOSE | ||
258 | * Look-up the inode for a given name. | ||
259 | * | ||
260 | * DESCRIPTION | ||
261 | * Required - lookup_dentry() will return -ENOTDIR if this routine is not | ||
262 | * available for a directory. The filesystem is useless if this routine is | ||
263 | * not available for at least the filesystem's root directory. | ||
264 | * | ||
265 | * This routine is passed an incomplete dentry - it must be completed by | ||
266 | * calling d_add(dentry, inode). If the name does not exist, then the | ||
267 | * specified inode must be set to null. An error should only be returned | ||
268 | * when the lookup fails for a reason other than the name not existing. | ||
269 | * Note that the directory inode semaphore is held during the call. | ||
270 | * | ||
271 | * Refer to lookup_dentry() in fs/namei.c | ||
272 | * lookup_dentry() -> lookup() -> real_lookup() -> . | ||
273 | * | ||
274 | * PRE-CONDITIONS | ||
275 | * dir Pointer to inode of parent directory. | ||
276 | * dentry Pointer to dentry to complete. | ||
277 | * nd Pointer to lookup nameidata | ||
278 | * | ||
279 | * POST-CONDITIONS | ||
280 | * <return> Zero on success. | ||
281 | * | ||
282 | * HISTORY | ||
283 | * July 1, 1997 - Andrew E. Mileski | ||
284 | * Written, tested, and released. | ||
285 | */ | ||
286 | |||
287 | static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, | 249 | static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, |
288 | struct nameidata *nd) | 250 | struct nameidata *nd) |
289 | { | 251 | { |
@@ -336,11 +298,9 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
336 | { | 298 | { |
337 | struct super_block *sb = dir->i_sb; | 299 | struct super_block *sb = dir->i_sb; |
338 | struct fileIdentDesc *fi = NULL; | 300 | struct fileIdentDesc *fi = NULL; |
339 | char name[UDF_NAME_LEN], fname[UDF_NAME_LEN]; | 301 | char *name = NULL; |
340 | int namelen; | 302 | int namelen; |
341 | loff_t f_pos; | 303 | loff_t f_pos; |
342 | int flen; | ||
343 | char *nameptr; | ||
344 | loff_t size = udf_ext0_offset(dir) + dir->i_size; | 304 | loff_t size = udf_ext0_offset(dir) + dir->i_size; |
345 | int nfidlen; | 305 | int nfidlen; |
346 | uint8_t lfi; | 306 | uint8_t lfi; |
@@ -352,16 +312,23 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
352 | struct extent_position epos = {}; | 312 | struct extent_position epos = {}; |
353 | struct udf_inode_info *dinfo; | 313 | struct udf_inode_info *dinfo; |
354 | 314 | ||
315 | fibh->sbh = fibh->ebh = NULL; | ||
316 | name = kmalloc(UDF_NAME_LEN, GFP_NOFS); | ||
317 | if (!name) { | ||
318 | *err = -ENOMEM; | ||
319 | goto out_err; | ||
320 | } | ||
321 | |||
355 | if (dentry) { | 322 | if (dentry) { |
356 | if (!dentry->d_name.len) { | 323 | if (!dentry->d_name.len) { |
357 | *err = -EINVAL; | 324 | *err = -EINVAL; |
358 | return NULL; | 325 | goto out_err; |
359 | } | 326 | } |
360 | namelen = udf_put_filename(sb, dentry->d_name.name, name, | 327 | namelen = udf_put_filename(sb, dentry->d_name.name, name, |
361 | dentry->d_name.len); | 328 | dentry->d_name.len); |
362 | if (!namelen) { | 329 | if (!namelen) { |
363 | *err = -ENAMETOOLONG; | 330 | *err = -ENAMETOOLONG; |
364 | return NULL; | 331 | goto out_err; |
365 | } | 332 | } |
366 | } else { | 333 | } else { |
367 | namelen = 0; | 334 | namelen = 0; |
@@ -373,11 +340,14 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
373 | 340 | ||
374 | fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); | 341 | fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); |
375 | dinfo = UDF_I(dir); | 342 | dinfo = UDF_I(dir); |
376 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) | 343 | if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { |
377 | fibh->sbh = fibh->ebh = NULL; | 344 | if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos, |
378 | else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, | 345 | &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) { |
379 | &epos, &eloc, &elen, &offset) == | 346 | block = udf_get_lb_pblock(dir->i_sb, |
380 | (EXT_RECORDED_ALLOCATED >> 30)) { | 347 | dinfo->i_location, 0); |
348 | fibh->soffset = fibh->eoffset = sb->s_blocksize; | ||
349 | goto add; | ||
350 | } | ||
381 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); | 351 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); |
382 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { | 352 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { |
383 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) | 353 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) |
@@ -389,17 +359,11 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
389 | 359 | ||
390 | fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); | 360 | fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); |
391 | if (!fibh->sbh) { | 361 | if (!fibh->sbh) { |
392 | brelse(epos.bh); | ||
393 | *err = -EIO; | 362 | *err = -EIO; |
394 | return NULL; | 363 | goto out_err; |
395 | } | 364 | } |
396 | 365 | ||
397 | block = dinfo->i_location.logicalBlockNum; | 366 | block = dinfo->i_location.logicalBlockNum; |
398 | } else { | ||
399 | block = udf_get_lb_pblock(dir->i_sb, dinfo->i_location, 0); | ||
400 | fibh->sbh = fibh->ebh = NULL; | ||
401 | fibh->soffset = fibh->eoffset = sb->s_blocksize; | ||
402 | goto add; | ||
403 | } | 367 | } |
404 | 368 | ||
405 | while (f_pos < size) { | 369 | while (f_pos < size) { |
@@ -407,41 +371,16 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
407 | &elen, &offset); | 371 | &elen, &offset); |
408 | 372 | ||
409 | if (!fi) { | 373 | if (!fi) { |
410 | if (fibh->sbh != fibh->ebh) | ||
411 | brelse(fibh->ebh); | ||
412 | brelse(fibh->sbh); | ||
413 | brelse(epos.bh); | ||
414 | *err = -EIO; | 374 | *err = -EIO; |
415 | return NULL; | 375 | goto out_err; |
416 | } | 376 | } |
417 | 377 | ||
418 | liu = le16_to_cpu(cfi->lengthOfImpUse); | 378 | liu = le16_to_cpu(cfi->lengthOfImpUse); |
419 | lfi = cfi->lengthFileIdent; | 379 | lfi = cfi->lengthFileIdent; |
420 | 380 | ||
421 | if (fibh->sbh == fibh->ebh) | ||
422 | nameptr = fi->fileIdent + liu; | ||
423 | else { | ||
424 | int poffset; /* Unpaded ending offset */ | ||
425 | |||
426 | poffset = fibh->soffset + sizeof(struct fileIdentDesc) + | ||
427 | liu + lfi; | ||
428 | |||
429 | if (poffset >= lfi) | ||
430 | nameptr = (char *)(fibh->ebh->b_data + | ||
431 | poffset - lfi); | ||
432 | else { | ||
433 | nameptr = fname; | ||
434 | memcpy(nameptr, fi->fileIdent + liu, | ||
435 | lfi - poffset); | ||
436 | memcpy(nameptr + lfi - poffset, | ||
437 | fibh->ebh->b_data, poffset); | ||
438 | } | ||
439 | } | ||
440 | |||
441 | if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) { | 381 | if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) { |
442 | if (((sizeof(struct fileIdentDesc) + | 382 | if (((sizeof(struct fileIdentDesc) + |
443 | liu + lfi + 3) & ~3) == nfidlen) { | 383 | liu + lfi + 3) & ~3) == nfidlen) { |
444 | brelse(epos.bh); | ||
445 | cfi->descTag.tagSerialNum = cpu_to_le16(1); | 384 | cfi->descTag.tagSerialNum = cpu_to_le16(1); |
446 | cfi->fileVersionNum = cpu_to_le16(1); | 385 | cfi->fileVersionNum = cpu_to_le16(1); |
447 | cfi->fileCharacteristics = 0; | 386 | cfi->fileCharacteristics = 0; |
@@ -449,27 +388,13 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
449 | cfi->lengthOfImpUse = cpu_to_le16(0); | 388 | cfi->lengthOfImpUse = cpu_to_le16(0); |
450 | if (!udf_write_fi(dir, cfi, fi, fibh, NULL, | 389 | if (!udf_write_fi(dir, cfi, fi, fibh, NULL, |
451 | name)) | 390 | name)) |
452 | return fi; | 391 | goto out_ok; |
453 | else { | 392 | else { |
454 | *err = -EIO; | 393 | *err = -EIO; |
455 | return NULL; | 394 | goto out_err; |
456 | } | 395 | } |
457 | } | 396 | } |
458 | } | 397 | } |
459 | |||
460 | if (!lfi || !dentry) | ||
461 | continue; | ||
462 | |||
463 | flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); | ||
464 | if (flen && udf_match(flen, fname, dentry->d_name.len, | ||
465 | dentry->d_name.name)) { | ||
466 | if (fibh->sbh != fibh->ebh) | ||
467 | brelse(fibh->ebh); | ||
468 | brelse(fibh->sbh); | ||
469 | brelse(epos.bh); | ||
470 | *err = -EEXIST; | ||
471 | return NULL; | ||
472 | } | ||
473 | } | 398 | } |
474 | 399 | ||
475 | add: | 400 | add: |
@@ -496,7 +421,7 @@ add: | |||
496 | fibh->sbh = fibh->ebh = | 421 | fibh->sbh = fibh->ebh = |
497 | udf_expand_dir_adinicb(dir, &block, err); | 422 | udf_expand_dir_adinicb(dir, &block, err); |
498 | if (!fibh->sbh) | 423 | if (!fibh->sbh) |
499 | return NULL; | 424 | goto out_err; |
500 | epos.block = dinfo->i_location; | 425 | epos.block = dinfo->i_location; |
501 | epos.offset = udf_file_entry_alloc_offset(dir); | 426 | epos.offset = udf_file_entry_alloc_offset(dir); |
502 | /* Load extent udf_expand_dir_adinicb() has created */ | 427 | /* Load extent udf_expand_dir_adinicb() has created */ |
@@ -537,11 +462,8 @@ add: | |||
537 | dir->i_sb->s_blocksize_bits); | 462 | dir->i_sb->s_blocksize_bits); |
538 | fibh->ebh = udf_bread(dir, | 463 | fibh->ebh = udf_bread(dir, |
539 | f_pos >> dir->i_sb->s_blocksize_bits, 1, err); | 464 | f_pos >> dir->i_sb->s_blocksize_bits, 1, err); |
540 | if (!fibh->ebh) { | 465 | if (!fibh->ebh) |
541 | brelse(epos.bh); | 466 | goto out_err; |
542 | brelse(fibh->sbh); | ||
543 | return NULL; | ||
544 | } | ||
545 | 467 | ||
546 | if (!fibh->soffset) { | 468 | if (!fibh->soffset) { |
547 | if (udf_next_aext(dir, &epos, &eloc, &elen, 1) == | 469 | if (udf_next_aext(dir, &epos, &eloc, &elen, 1) == |
@@ -572,20 +494,25 @@ add: | |||
572 | cfi->lengthFileIdent = namelen; | 494 | cfi->lengthFileIdent = namelen; |
573 | cfi->lengthOfImpUse = cpu_to_le16(0); | 495 | cfi->lengthOfImpUse = cpu_to_le16(0); |
574 | if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) { | 496 | if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) { |
575 | brelse(epos.bh); | ||
576 | dir->i_size += nfidlen; | 497 | dir->i_size += nfidlen; |
577 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) | 498 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) |
578 | dinfo->i_lenAlloc += nfidlen; | 499 | dinfo->i_lenAlloc += nfidlen; |
579 | mark_inode_dirty(dir); | 500 | mark_inode_dirty(dir); |
580 | return fi; | 501 | goto out_ok; |
581 | } else { | 502 | } else { |
582 | brelse(epos.bh); | ||
583 | if (fibh->sbh != fibh->ebh) | ||
584 | brelse(fibh->ebh); | ||
585 | brelse(fibh->sbh); | ||
586 | *err = -EIO; | 503 | *err = -EIO; |
587 | return NULL; | 504 | goto out_err; |
588 | } | 505 | } |
506 | |||
507 | out_err: | ||
508 | fi = NULL; | ||
509 | if (fibh->sbh != fibh->ebh) | ||
510 | brelse(fibh->ebh); | ||
511 | brelse(fibh->sbh); | ||
512 | out_ok: | ||
513 | brelse(epos.bh); | ||
514 | kfree(name); | ||
515 | return fi; | ||
589 | } | 516 | } |
590 | 517 | ||
591 | static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi, | 518 | static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi, |
@@ -940,7 +867,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, | |||
940 | char *ea; | 867 | char *ea; |
941 | int err; | 868 | int err; |
942 | int block; | 869 | int block; |
943 | char name[UDF_NAME_LEN]; | 870 | char *name = NULL; |
944 | int namelen; | 871 | int namelen; |
945 | struct buffer_head *bh; | 872 | struct buffer_head *bh; |
946 | struct udf_inode_info *iinfo; | 873 | struct udf_inode_info *iinfo; |
@@ -950,6 +877,12 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, | |||
950 | if (!inode) | 877 | if (!inode) |
951 | goto out; | 878 | goto out; |
952 | 879 | ||
880 | name = kmalloc(UDF_NAME_LEN, GFP_NOFS); | ||
881 | if (!name) { | ||
882 | err = -ENOMEM; | ||
883 | goto out_no_entry; | ||
884 | } | ||
885 | |||
953 | iinfo = UDF_I(inode); | 886 | iinfo = UDF_I(inode); |
954 | inode->i_mode = S_IFLNK | S_IRWXUGO; | 887 | inode->i_mode = S_IFLNK | S_IRWXUGO; |
955 | inode->i_data.a_ops = &udf_symlink_aops; | 888 | inode->i_data.a_ops = &udf_symlink_aops; |
@@ -1089,6 +1022,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, | |||
1089 | err = 0; | 1022 | err = 0; |
1090 | 1023 | ||
1091 | out: | 1024 | out: |
1025 | kfree(name); | ||
1092 | unlock_kernel(); | 1026 | unlock_kernel(); |
1093 | return err; | 1027 | return err; |
1094 | 1028 | ||
diff --git a/fs/udf/partition.c b/fs/udf/partition.c index fc533345ab89..63610f026ae1 100644 --- a/fs/udf/partition.c +++ b/fs/udf/partition.c | |||
@@ -24,7 +24,6 @@ | |||
24 | 24 | ||
25 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
26 | #include <linux/string.h> | 26 | #include <linux/string.h> |
27 | #include <linux/udf_fs.h> | ||
28 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
29 | #include <linux/buffer_head.h> | 28 | #include <linux/buffer_head.h> |
30 | 29 | ||
@@ -55,11 +54,10 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, | |||
55 | struct udf_sb_info *sbi = UDF_SB(sb); | 54 | struct udf_sb_info *sbi = UDF_SB(sb); |
56 | struct udf_part_map *map; | 55 | struct udf_part_map *map; |
57 | struct udf_virtual_data *vdata; | 56 | struct udf_virtual_data *vdata; |
58 | struct udf_inode_info *iinfo; | 57 | struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode); |
59 | 58 | ||
60 | map = &sbi->s_partmaps[partition]; | 59 | map = &sbi->s_partmaps[partition]; |
61 | vdata = &map->s_type_specific.s_virtual; | 60 | vdata = &map->s_type_specific.s_virtual; |
62 | index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t); | ||
63 | 61 | ||
64 | if (block > vdata->s_num_entries) { | 62 | if (block > vdata->s_num_entries) { |
65 | udf_debug("Trying to access block beyond end of VAT " | 63 | udf_debug("Trying to access block beyond end of VAT " |
@@ -67,6 +65,12 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, | |||
67 | return 0xFFFFFFFF; | 65 | return 0xFFFFFFFF; |
68 | } | 66 | } |
69 | 67 | ||
68 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { | ||
69 | loc = le32_to_cpu(((__le32 *)(iinfo->i_ext.i_data + | ||
70 | vdata->s_start_offset))[block]); | ||
71 | goto translate; | ||
72 | } | ||
73 | index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t); | ||
70 | if (block >= index) { | 74 | if (block >= index) { |
71 | block -= index; | 75 | block -= index; |
72 | newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t))); | 76 | newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t))); |
@@ -89,7 +93,7 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, | |||
89 | 93 | ||
90 | brelse(bh); | 94 | brelse(bh); |
91 | 95 | ||
92 | iinfo = UDF_I(sbi->s_vat_inode); | 96 | translate: |
93 | if (iinfo->i_location.partitionReferenceNum == partition) { | 97 | if (iinfo->i_location.partitionReferenceNum == partition) { |
94 | udf_debug("recursive call to udf_get_pblock!\n"); | 98 | udf_debug("recursive call to udf_get_pblock!\n"); |
95 | return 0xFFFFFFFF; | 99 | return 0xFFFFFFFF; |
@@ -263,3 +267,58 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block) | |||
263 | 267 | ||
264 | return 0; | 268 | return 0; |
265 | } | 269 | } |
270 | |||
271 | static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block, | ||
272 | uint16_t partition, uint32_t offset) | ||
273 | { | ||
274 | struct super_block *sb = inode->i_sb; | ||
275 | struct udf_part_map *map; | ||
276 | kernel_lb_addr eloc; | ||
277 | uint32_t elen; | ||
278 | sector_t ext_offset; | ||
279 | struct extent_position epos = {}; | ||
280 | uint32_t phyblock; | ||
281 | |||
282 | if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) != | ||
283 | (EXT_RECORDED_ALLOCATED >> 30)) | ||
284 | phyblock = 0xFFFFFFFF; | ||
285 | else { | ||
286 | map = &UDF_SB(sb)->s_partmaps[partition]; | ||
287 | /* map to sparable/physical partition desc */ | ||
288 | phyblock = udf_get_pblock(sb, eloc.logicalBlockNum, | ||
289 | map->s_partition_num, ext_offset + offset); | ||
290 | } | ||
291 | |||
292 | brelse(epos.bh); | ||
293 | return phyblock; | ||
294 | } | ||
295 | |||
296 | uint32_t udf_get_pblock_meta25(struct super_block *sb, uint32_t block, | ||
297 | uint16_t partition, uint32_t offset) | ||
298 | { | ||
299 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
300 | struct udf_part_map *map; | ||
301 | struct udf_meta_data *mdata; | ||
302 | uint32_t retblk; | ||
303 | struct inode *inode; | ||
304 | |||
305 | udf_debug("READING from METADATA\n"); | ||
306 | |||
307 | map = &sbi->s_partmaps[partition]; | ||
308 | mdata = &map->s_type_specific.s_metadata; | ||
309 | inode = mdata->s_metadata_fe ? : mdata->s_mirror_fe; | ||
310 | |||
311 | /* We shouldn't mount such media... */ | ||
312 | BUG_ON(!inode); | ||
313 | retblk = udf_try_read_meta(inode, block, partition, offset); | ||
314 | if (retblk == 0xFFFFFFFF) { | ||
315 | udf_warning(sb, __func__, "error reading from METADATA, " | ||
316 | "trying to read from MIRROR"); | ||
317 | inode = mdata->s_mirror_fe; | ||
318 | if (!inode) | ||
319 | return 0xFFFFFFFF; | ||
320 | retblk = udf_try_read_meta(inode, block, partition, offset); | ||
321 | } | ||
322 | |||
323 | return retblk; | ||
324 | } | ||
diff --git a/fs/udf/super.c b/fs/udf/super.c index f3ac4abfc946..b564fc140fe4 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
@@ -55,9 +55,10 @@ | |||
55 | #include <linux/errno.h> | 55 | #include <linux/errno.h> |
56 | #include <linux/mount.h> | 56 | #include <linux/mount.h> |
57 | #include <linux/seq_file.h> | 57 | #include <linux/seq_file.h> |
58 | #include <linux/bitmap.h> | ||
59 | #include <linux/crc-itu-t.h> | ||
58 | #include <asm/byteorder.h> | 60 | #include <asm/byteorder.h> |
59 | 61 | ||
60 | #include <linux/udf_fs.h> | ||
61 | #include "udf_sb.h" | 62 | #include "udf_sb.h" |
62 | #include "udf_i.h" | 63 | #include "udf_i.h" |
63 | 64 | ||
@@ -84,22 +85,19 @@ static void udf_write_super(struct super_block *); | |||
84 | static int udf_remount_fs(struct super_block *, int *, char *); | 85 | static int udf_remount_fs(struct super_block *, int *, char *); |
85 | static int udf_check_valid(struct super_block *, int, int); | 86 | static int udf_check_valid(struct super_block *, int, int); |
86 | static int udf_vrs(struct super_block *sb, int silent); | 87 | static int udf_vrs(struct super_block *sb, int silent); |
87 | static int udf_load_partition(struct super_block *, kernel_lb_addr *); | ||
88 | static int udf_load_logicalvol(struct super_block *, struct buffer_head *, | ||
89 | kernel_lb_addr *); | ||
90 | static void udf_load_logicalvolint(struct super_block *, kernel_extent_ad); | 88 | static void udf_load_logicalvolint(struct super_block *, kernel_extent_ad); |
91 | static void udf_find_anchor(struct super_block *); | 89 | static void udf_find_anchor(struct super_block *); |
92 | static int udf_find_fileset(struct super_block *, kernel_lb_addr *, | 90 | static int udf_find_fileset(struct super_block *, kernel_lb_addr *, |
93 | kernel_lb_addr *); | 91 | kernel_lb_addr *); |
94 | static void udf_load_pvoldesc(struct super_block *, struct buffer_head *); | ||
95 | static void udf_load_fileset(struct super_block *, struct buffer_head *, | 92 | static void udf_load_fileset(struct super_block *, struct buffer_head *, |
96 | kernel_lb_addr *); | 93 | kernel_lb_addr *); |
97 | static int udf_load_partdesc(struct super_block *, struct buffer_head *); | ||
98 | static void udf_open_lvid(struct super_block *); | 94 | static void udf_open_lvid(struct super_block *); |
99 | static void udf_close_lvid(struct super_block *); | 95 | static void udf_close_lvid(struct super_block *); |
100 | static unsigned int udf_count_free(struct super_block *); | 96 | static unsigned int udf_count_free(struct super_block *); |
101 | static int udf_statfs(struct dentry *, struct kstatfs *); | 97 | static int udf_statfs(struct dentry *, struct kstatfs *); |
102 | static int udf_show_options(struct seq_file *, struct vfsmount *); | 98 | static int udf_show_options(struct seq_file *, struct vfsmount *); |
99 | static void udf_error(struct super_block *sb, const char *function, | ||
100 | const char *fmt, ...); | ||
103 | 101 | ||
104 | struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi) | 102 | struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi) |
105 | { | 103 | { |
@@ -587,48 +585,10 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) | |||
587 | return 0; | 585 | return 0; |
588 | } | 586 | } |
589 | 587 | ||
590 | /* | ||
591 | * udf_set_blocksize | ||
592 | * | ||
593 | * PURPOSE | ||
594 | * Set the block size to be used in all transfers. | ||
595 | * | ||
596 | * DESCRIPTION | ||
597 | * To allow room for a DMA transfer, it is best to guess big when unsure. | ||
598 | * This routine picks 2048 bytes as the blocksize when guessing. This | ||
599 | * should be adequate until devices with larger block sizes become common. | ||
600 | * | ||
601 | * Note that the Linux kernel can currently only deal with blocksizes of | ||
602 | * 512, 1024, 2048, 4096, and 8192 bytes. | ||
603 | * | ||
604 | * PRE-CONDITIONS | ||
605 | * sb Pointer to _locked_ superblock. | ||
606 | * | ||
607 | * POST-CONDITIONS | ||
608 | * sb->s_blocksize Blocksize. | ||
609 | * sb->s_blocksize_bits log2 of blocksize. | ||
610 | * <return> 0 Blocksize is valid. | ||
611 | * <return> 1 Blocksize is invalid. | ||
612 | * | ||
613 | * HISTORY | ||
614 | * July 1, 1997 - Andrew E. Mileski | ||
615 | * Written, tested, and released. | ||
616 | */ | ||
617 | static int udf_set_blocksize(struct super_block *sb, int bsize) | ||
618 | { | ||
619 | if (!sb_min_blocksize(sb, bsize)) { | ||
620 | udf_debug("Bad block size (%d)\n", bsize); | ||
621 | printk(KERN_ERR "udf: bad block size (%d)\n", bsize); | ||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | return sb->s_blocksize; | ||
626 | } | ||
627 | |||
628 | static int udf_vrs(struct super_block *sb, int silent) | 588 | static int udf_vrs(struct super_block *sb, int silent) |
629 | { | 589 | { |
630 | struct volStructDesc *vsd = NULL; | 590 | struct volStructDesc *vsd = NULL; |
631 | int sector = 32768; | 591 | loff_t sector = 32768; |
632 | int sectorsize; | 592 | int sectorsize; |
633 | struct buffer_head *bh = NULL; | 593 | struct buffer_head *bh = NULL; |
634 | int iso9660 = 0; | 594 | int iso9660 = 0; |
@@ -649,7 +609,8 @@ static int udf_vrs(struct super_block *sb, int silent) | |||
649 | sector += (sbi->s_session << sb->s_blocksize_bits); | 609 | sector += (sbi->s_session << sb->s_blocksize_bits); |
650 | 610 | ||
651 | udf_debug("Starting at sector %u (%ld byte sectors)\n", | 611 | udf_debug("Starting at sector %u (%ld byte sectors)\n", |
652 | (sector >> sb->s_blocksize_bits), sb->s_blocksize); | 612 | (unsigned int)(sector >> sb->s_blocksize_bits), |
613 | sb->s_blocksize); | ||
653 | /* Process the sequence (if applicable) */ | 614 | /* Process the sequence (if applicable) */ |
654 | for (; !nsr02 && !nsr03; sector += sectorsize) { | 615 | for (; !nsr02 && !nsr03; sector += sectorsize) { |
655 | /* Read a block */ | 616 | /* Read a block */ |
@@ -719,162 +680,140 @@ static int udf_vrs(struct super_block *sb, int silent) | |||
719 | } | 680 | } |
720 | 681 | ||
721 | /* | 682 | /* |
722 | * udf_find_anchor | 683 | * Check whether there is an anchor block in the given block |
723 | * | ||
724 | * PURPOSE | ||
725 | * Find an anchor volume descriptor. | ||
726 | * | ||
727 | * PRE-CONDITIONS | ||
728 | * sb Pointer to _locked_ superblock. | ||
729 | * lastblock Last block on media. | ||
730 | * | ||
731 | * POST-CONDITIONS | ||
732 | * <return> 1 if not found, 0 if ok | ||
733 | * | ||
734 | * HISTORY | ||
735 | * July 1, 1997 - Andrew E. Mileski | ||
736 | * Written, tested, and released. | ||
737 | */ | 684 | */ |
738 | static void udf_find_anchor(struct super_block *sb) | 685 | static int udf_check_anchor_block(struct super_block *sb, sector_t block, |
686 | bool varconv) | ||
739 | { | 687 | { |
740 | int lastblock; | ||
741 | struct buffer_head *bh = NULL; | 688 | struct buffer_head *bh = NULL; |
689 | tag *t; | ||
742 | uint16_t ident; | 690 | uint16_t ident; |
743 | uint32_t location; | 691 | uint32_t location; |
744 | int i; | ||
745 | struct udf_sb_info *sbi; | ||
746 | 692 | ||
747 | sbi = UDF_SB(sb); | 693 | if (varconv) { |
748 | lastblock = sbi->s_last_block; | 694 | if (udf_fixed_to_variable(block) >= |
695 | sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) | ||
696 | return 0; | ||
697 | bh = sb_bread(sb, udf_fixed_to_variable(block)); | ||
698 | } | ||
699 | else | ||
700 | bh = sb_bread(sb, block); | ||
749 | 701 | ||
750 | if (lastblock) { | 702 | if (!bh) |
751 | int varlastblock = udf_variable_to_fixed(lastblock); | 703 | return 0; |
752 | int last[] = { lastblock, lastblock - 2, | ||
753 | lastblock - 150, lastblock - 152, | ||
754 | varlastblock, varlastblock - 2, | ||
755 | varlastblock - 150, varlastblock - 152 }; | ||
756 | |||
757 | lastblock = 0; | ||
758 | |||
759 | /* Search for an anchor volume descriptor pointer */ | ||
760 | |||
761 | /* according to spec, anchor is in either: | ||
762 | * block 256 | ||
763 | * lastblock-256 | ||
764 | * lastblock | ||
765 | * however, if the disc isn't closed, it could be 512 */ | ||
766 | |||
767 | for (i = 0; !lastblock && i < ARRAY_SIZE(last); i++) { | ||
768 | ident = location = 0; | ||
769 | if (last[i] >= 0) { | ||
770 | bh = sb_bread(sb, last[i]); | ||
771 | if (bh) { | ||
772 | tag *t = (tag *)bh->b_data; | ||
773 | ident = le16_to_cpu(t->tagIdent); | ||
774 | location = le32_to_cpu(t->tagLocation); | ||
775 | brelse(bh); | ||
776 | } | ||
777 | } | ||
778 | 704 | ||
779 | if (ident == TAG_IDENT_AVDP) { | 705 | t = (tag *)bh->b_data; |
780 | if (location == last[i] - sbi->s_session) { | 706 | ident = le16_to_cpu(t->tagIdent); |
781 | lastblock = last[i] - sbi->s_session; | 707 | location = le32_to_cpu(t->tagLocation); |
782 | sbi->s_anchor[0] = lastblock; | 708 | brelse(bh); |
783 | sbi->s_anchor[1] = lastblock - 256; | 709 | if (ident != TAG_IDENT_AVDP) |
784 | } else if (location == | 710 | return 0; |
785 | udf_variable_to_fixed(last[i]) - | 711 | return location == block; |
786 | sbi->s_session) { | 712 | } |
787 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | ||
788 | lastblock = | ||
789 | udf_variable_to_fixed(last[i]) - | ||
790 | sbi->s_session; | ||
791 | sbi->s_anchor[0] = lastblock; | ||
792 | sbi->s_anchor[1] = lastblock - 256 - | ||
793 | sbi->s_session; | ||
794 | } else { | ||
795 | udf_debug("Anchor found at block %d, " | ||
796 | "location mismatch %d.\n", | ||
797 | last[i], location); | ||
798 | } | ||
799 | } else if (ident == TAG_IDENT_FE || | ||
800 | ident == TAG_IDENT_EFE) { | ||
801 | lastblock = last[i]; | ||
802 | sbi->s_anchor[3] = 512; | ||
803 | } else { | ||
804 | ident = location = 0; | ||
805 | if (last[i] >= 256) { | ||
806 | bh = sb_bread(sb, last[i] - 256); | ||
807 | if (bh) { | ||
808 | tag *t = (tag *)bh->b_data; | ||
809 | ident = le16_to_cpu( | ||
810 | t->tagIdent); | ||
811 | location = le32_to_cpu( | ||
812 | t->tagLocation); | ||
813 | brelse(bh); | ||
814 | } | ||
815 | } | ||
816 | 713 | ||
817 | if (ident == TAG_IDENT_AVDP && | 714 | /* Search for an anchor volume descriptor pointer */ |
818 | location == last[i] - 256 - | 715 | static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, |
819 | sbi->s_session) { | 716 | sector_t lastblock) |
820 | lastblock = last[i]; | 717 | { |
821 | sbi->s_anchor[1] = last[i] - 256; | 718 | sector_t last[6]; |
822 | } else { | 719 | int i; |
823 | ident = location = 0; | 720 | struct udf_sb_info *sbi = UDF_SB(sb); |
824 | if (last[i] >= 312 + sbi->s_session) { | ||
825 | bh = sb_bread(sb, | ||
826 | last[i] - 312 - | ||
827 | sbi->s_session); | ||
828 | if (bh) { | ||
829 | tag *t = (tag *) | ||
830 | bh->b_data; | ||
831 | ident = le16_to_cpu( | ||
832 | t->tagIdent); | ||
833 | location = le32_to_cpu( | ||
834 | t->tagLocation); | ||
835 | brelse(bh); | ||
836 | } | ||
837 | } | ||
838 | 721 | ||
839 | if (ident == TAG_IDENT_AVDP && | 722 | last[0] = lastblock; |
840 | location == udf_variable_to_fixed(last[i]) - 256) { | 723 | last[1] = last[0] - 1; |
841 | UDF_SET_FLAG(sb, | 724 | last[2] = last[0] + 1; |
842 | UDF_FLAG_VARCONV); | 725 | last[3] = last[0] - 2; |
843 | lastblock = udf_variable_to_fixed(last[i]); | 726 | last[4] = last[0] - 150; |
844 | sbi->s_anchor[1] = lastblock - 256; | 727 | last[5] = last[0] - 152; |
845 | } | 728 | |
846 | } | 729 | /* according to spec, anchor is in either: |
847 | } | 730 | * block 256 |
731 | * lastblock-256 | ||
732 | * lastblock | ||
733 | * however, if the disc isn't closed, it could be 512 */ | ||
734 | |||
735 | for (i = 0; i < ARRAY_SIZE(last); i++) { | ||
736 | if (last[i] < 0) | ||
737 | continue; | ||
738 | if (last[i] >= sb->s_bdev->bd_inode->i_size >> | ||
739 | sb->s_blocksize_bits) | ||
740 | continue; | ||
741 | |||
742 | if (udf_check_anchor_block(sb, last[i], varconv)) { | ||
743 | sbi->s_anchor[0] = last[i]; | ||
744 | sbi->s_anchor[1] = last[i] - 256; | ||
745 | return last[i]; | ||
848 | } | 746 | } |
849 | } | ||
850 | 747 | ||
851 | if (!lastblock) { | 748 | if (last[i] < 256) |
852 | /* We haven't found the lastblock. check 312 */ | 749 | continue; |
853 | bh = sb_bread(sb, 312 + sbi->s_session); | ||
854 | if (bh) { | ||
855 | tag *t = (tag *)bh->b_data; | ||
856 | ident = le16_to_cpu(t->tagIdent); | ||
857 | location = le32_to_cpu(t->tagLocation); | ||
858 | brelse(bh); | ||
859 | 750 | ||
860 | if (ident == TAG_IDENT_AVDP && location == 256) | 751 | if (udf_check_anchor_block(sb, last[i] - 256, varconv)) { |
861 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | 752 | sbi->s_anchor[1] = last[i] - 256; |
753 | return last[i]; | ||
862 | } | 754 | } |
863 | } | 755 | } |
864 | 756 | ||
757 | if (udf_check_anchor_block(sb, sbi->s_session + 256, varconv)) { | ||
758 | sbi->s_anchor[0] = sbi->s_session + 256; | ||
759 | return last[0]; | ||
760 | } | ||
761 | if (udf_check_anchor_block(sb, sbi->s_session + 512, varconv)) { | ||
762 | sbi->s_anchor[0] = sbi->s_session + 512; | ||
763 | return last[0]; | ||
764 | } | ||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | /* | ||
769 | * Find an anchor volume descriptor. The function expects sbi->s_lastblock to | ||
770 | * be the last block on the media. | ||
771 | * | ||
772 | * Return 1 if not found, 0 if ok | ||
773 | * | ||
774 | */ | ||
775 | static void udf_find_anchor(struct super_block *sb) | ||
776 | { | ||
777 | sector_t lastblock; | ||
778 | struct buffer_head *bh = NULL; | ||
779 | uint16_t ident; | ||
780 | int i; | ||
781 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
782 | |||
783 | lastblock = udf_scan_anchors(sb, 0, sbi->s_last_block); | ||
784 | if (lastblock) | ||
785 | goto check_anchor; | ||
786 | |||
787 | /* No anchor found? Try VARCONV conversion of block numbers */ | ||
788 | /* Firstly, we try to not convert number of the last block */ | ||
789 | lastblock = udf_scan_anchors(sb, 1, | ||
790 | udf_variable_to_fixed(sbi->s_last_block)); | ||
791 | if (lastblock) { | ||
792 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | ||
793 | goto check_anchor; | ||
794 | } | ||
795 | |||
796 | /* Secondly, we try with converted number of the last block */ | ||
797 | lastblock = udf_scan_anchors(sb, 1, sbi->s_last_block); | ||
798 | if (lastblock) | ||
799 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | ||
800 | |||
801 | check_anchor: | ||
802 | /* | ||
803 | * Check located anchors and the anchor block supplied via | ||
804 | * mount options | ||
805 | */ | ||
865 | for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { | 806 | for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { |
866 | if (sbi->s_anchor[i]) { | 807 | if (!sbi->s_anchor[i]) |
867 | bh = udf_read_tagged(sb, sbi->s_anchor[i], | 808 | continue; |
868 | sbi->s_anchor[i], &ident); | 809 | bh = udf_read_tagged(sb, sbi->s_anchor[i], |
869 | if (!bh) | 810 | sbi->s_anchor[i], &ident); |
811 | if (!bh) | ||
812 | sbi->s_anchor[i] = 0; | ||
813 | else { | ||
814 | brelse(bh); | ||
815 | if (ident != TAG_IDENT_AVDP) | ||
870 | sbi->s_anchor[i] = 0; | 816 | sbi->s_anchor[i] = 0; |
871 | else { | ||
872 | brelse(bh); | ||
873 | if ((ident != TAG_IDENT_AVDP) && | ||
874 | (i || (ident != TAG_IDENT_FE && | ||
875 | ident != TAG_IDENT_EFE))) | ||
876 | sbi->s_anchor[i] = 0; | ||
877 | } | ||
878 | } | 817 | } |
879 | } | 818 | } |
880 | 819 | ||
@@ -971,27 +910,30 @@ static int udf_find_fileset(struct super_block *sb, | |||
971 | return 1; | 910 | return 1; |
972 | } | 911 | } |
973 | 912 | ||
974 | static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh) | 913 | static int udf_load_pvoldesc(struct super_block *sb, sector_t block) |
975 | { | 914 | { |
976 | struct primaryVolDesc *pvoldesc; | 915 | struct primaryVolDesc *pvoldesc; |
977 | time_t recording; | ||
978 | long recording_usec; | ||
979 | struct ustr instr; | 916 | struct ustr instr; |
980 | struct ustr outstr; | 917 | struct ustr outstr; |
918 | struct buffer_head *bh; | ||
919 | uint16_t ident; | ||
920 | |||
921 | bh = udf_read_tagged(sb, block, block, &ident); | ||
922 | if (!bh) | ||
923 | return 1; | ||
924 | BUG_ON(ident != TAG_IDENT_PVD); | ||
981 | 925 | ||
982 | pvoldesc = (struct primaryVolDesc *)bh->b_data; | 926 | pvoldesc = (struct primaryVolDesc *)bh->b_data; |
983 | 927 | ||
984 | if (udf_stamp_to_time(&recording, &recording_usec, | 928 | if (udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time, |
985 | lets_to_cpu(pvoldesc->recordingDateAndTime))) { | 929 | pvoldesc->recordingDateAndTime)) { |
986 | kernel_timestamp ts; | 930 | #ifdef UDFFS_DEBUG |
987 | ts = lets_to_cpu(pvoldesc->recordingDateAndTime); | 931 | timestamp *ts = &pvoldesc->recordingDateAndTime; |
988 | udf_debug("recording time %ld/%ld, %04u/%02u/%02u" | 932 | udf_debug("recording time %04u/%02u/%02u" |
989 | " %02u:%02u (%x)\n", | 933 | " %02u:%02u (%x)\n", |
990 | recording, recording_usec, | 934 | le16_to_cpu(ts->year), ts->month, ts->day, ts->hour, |
991 | ts.year, ts.month, ts.day, ts.hour, | 935 | ts->minute, le16_to_cpu(ts->typeAndTimezone)); |
992 | ts.minute, ts.typeAndTimezone); | 936 | #endif |
993 | UDF_SB(sb)->s_record_time.tv_sec = recording; | ||
994 | UDF_SB(sb)->s_record_time.tv_nsec = recording_usec * 1000; | ||
995 | } | 937 | } |
996 | 938 | ||
997 | if (!udf_build_ustr(&instr, pvoldesc->volIdent, 32)) | 939 | if (!udf_build_ustr(&instr, pvoldesc->volIdent, 32)) |
@@ -1005,6 +947,104 @@ static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh) | |||
1005 | if (!udf_build_ustr(&instr, pvoldesc->volSetIdent, 128)) | 947 | if (!udf_build_ustr(&instr, pvoldesc->volSetIdent, 128)) |
1006 | if (udf_CS0toUTF8(&outstr, &instr)) | 948 | if (udf_CS0toUTF8(&outstr, &instr)) |
1007 | udf_debug("volSetIdent[] = '%s'\n", outstr.u_name); | 949 | udf_debug("volSetIdent[] = '%s'\n", outstr.u_name); |
950 | |||
951 | brelse(bh); | ||
952 | return 0; | ||
953 | } | ||
954 | |||
955 | static int udf_load_metadata_files(struct super_block *sb, int partition) | ||
956 | { | ||
957 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
958 | struct udf_part_map *map; | ||
959 | struct udf_meta_data *mdata; | ||
960 | kernel_lb_addr addr; | ||
961 | int fe_error = 0; | ||
962 | |||
963 | map = &sbi->s_partmaps[partition]; | ||
964 | mdata = &map->s_type_specific.s_metadata; | ||
965 | |||
966 | /* metadata address */ | ||
967 | addr.logicalBlockNum = mdata->s_meta_file_loc; | ||
968 | addr.partitionReferenceNum = map->s_partition_num; | ||
969 | |||
970 | udf_debug("Metadata file location: block = %d part = %d\n", | ||
971 | addr.logicalBlockNum, addr.partitionReferenceNum); | ||
972 | |||
973 | mdata->s_metadata_fe = udf_iget(sb, addr); | ||
974 | |||
975 | if (mdata->s_metadata_fe == NULL) { | ||
976 | udf_warning(sb, __func__, "metadata inode efe not found, " | ||
977 | "will try mirror inode."); | ||
978 | fe_error = 1; | ||
979 | } else if (UDF_I(mdata->s_metadata_fe)->i_alloc_type != | ||
980 | ICBTAG_FLAG_AD_SHORT) { | ||
981 | udf_warning(sb, __func__, "metadata inode efe does not have " | ||
982 | "short allocation descriptors!"); | ||
983 | fe_error = 1; | ||
984 | iput(mdata->s_metadata_fe); | ||
985 | mdata->s_metadata_fe = NULL; | ||
986 | } | ||
987 | |||
988 | /* mirror file entry */ | ||
989 | addr.logicalBlockNum = mdata->s_mirror_file_loc; | ||
990 | addr.partitionReferenceNum = map->s_partition_num; | ||
991 | |||
992 | udf_debug("Mirror metadata file location: block = %d part = %d\n", | ||
993 | addr.logicalBlockNum, addr.partitionReferenceNum); | ||
994 | |||
995 | mdata->s_mirror_fe = udf_iget(sb, addr); | ||
996 | |||
997 | if (mdata->s_mirror_fe == NULL) { | ||
998 | if (fe_error) { | ||
999 | udf_error(sb, __func__, "mirror inode efe not found " | ||
1000 | "and metadata inode is missing too, exiting..."); | ||
1001 | goto error_exit; | ||
1002 | } else | ||
1003 | udf_warning(sb, __func__, "mirror inode efe not found," | ||
1004 | " but metadata inode is OK"); | ||
1005 | } else if (UDF_I(mdata->s_mirror_fe)->i_alloc_type != | ||
1006 | ICBTAG_FLAG_AD_SHORT) { | ||
1007 | udf_warning(sb, __func__, "mirror inode efe does not have " | ||
1008 | "short allocation descriptors!"); | ||
1009 | iput(mdata->s_mirror_fe); | ||
1010 | mdata->s_mirror_fe = NULL; | ||
1011 | if (fe_error) | ||
1012 | goto error_exit; | ||
1013 | } | ||
1014 | |||
1015 | /* | ||
1016 | * bitmap file entry | ||
1017 | * Note: | ||
1018 | * Load only if bitmap file location differs from 0xFFFFFFFF (DCN-5102) | ||
1019 | */ | ||
1020 | if (mdata->s_bitmap_file_loc != 0xFFFFFFFF) { | ||
1021 | addr.logicalBlockNum = mdata->s_bitmap_file_loc; | ||
1022 | addr.partitionReferenceNum = map->s_partition_num; | ||
1023 | |||
1024 | udf_debug("Bitmap file location: block = %d part = %d\n", | ||
1025 | addr.logicalBlockNum, addr.partitionReferenceNum); | ||
1026 | |||
1027 | mdata->s_bitmap_fe = udf_iget(sb, addr); | ||
1028 | |||
1029 | if (mdata->s_bitmap_fe == NULL) { | ||
1030 | if (sb->s_flags & MS_RDONLY) | ||
1031 | udf_warning(sb, __func__, "bitmap inode efe " | ||
1032 | "not found but it's ok since the disc" | ||
1033 | " is mounted read-only"); | ||
1034 | else { | ||
1035 | udf_error(sb, __func__, "bitmap inode efe not " | ||
1036 | "found and attempted read-write mount"); | ||
1037 | goto error_exit; | ||
1038 | } | ||
1039 | } | ||
1040 | } | ||
1041 | |||
1042 | udf_debug("udf_load_metadata_files Ok\n"); | ||
1043 | |||
1044 | return 0; | ||
1045 | |||
1046 | error_exit: | ||
1047 | return 1; | ||
1008 | } | 1048 | } |
1009 | 1049 | ||
1010 | static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, | 1050 | static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, |
@@ -1025,10 +1065,9 @@ static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, | |||
1025 | int udf_compute_nr_groups(struct super_block *sb, u32 partition) | 1065 | int udf_compute_nr_groups(struct super_block *sb, u32 partition) |
1026 | { | 1066 | { |
1027 | struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition]; | 1067 | struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition]; |
1028 | return (map->s_partition_len + | 1068 | return DIV_ROUND_UP(map->s_partition_len + |
1029 | (sizeof(struct spaceBitmapDesc) << 3) + | 1069 | (sizeof(struct spaceBitmapDesc) << 3), |
1030 | (sb->s_blocksize * 8) - 1) / | 1070 | sb->s_blocksize * 8); |
1031 | (sb->s_blocksize * 8); | ||
1032 | } | 1071 | } |
1033 | 1072 | ||
1034 | static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) | 1073 | static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) |
@@ -1059,134 +1098,241 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) | |||
1059 | return bitmap; | 1098 | return bitmap; |
1060 | } | 1099 | } |
1061 | 1100 | ||
1062 | static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) | 1101 | static int udf_fill_partdesc_info(struct super_block *sb, |
1102 | struct partitionDesc *p, int p_index) | ||
1103 | { | ||
1104 | struct udf_part_map *map; | ||
1105 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
1106 | struct partitionHeaderDesc *phd; | ||
1107 | |||
1108 | map = &sbi->s_partmaps[p_index]; | ||
1109 | |||
1110 | map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */ | ||
1111 | map->s_partition_root = le32_to_cpu(p->partitionStartingLocation); | ||
1112 | |||
1113 | if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY)) | ||
1114 | map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY; | ||
1115 | if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE)) | ||
1116 | map->s_partition_flags |= UDF_PART_FLAG_WRITE_ONCE; | ||
1117 | if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE)) | ||
1118 | map->s_partition_flags |= UDF_PART_FLAG_REWRITABLE; | ||
1119 | if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE)) | ||
1120 | map->s_partition_flags |= UDF_PART_FLAG_OVERWRITABLE; | ||
1121 | |||
1122 | udf_debug("Partition (%d type %x) starts at physical %d, " | ||
1123 | "block length %d\n", p_index, | ||
1124 | map->s_partition_type, map->s_partition_root, | ||
1125 | map->s_partition_len); | ||
1126 | |||
1127 | if (strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) && | ||
1128 | strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03)) | ||
1129 | return 0; | ||
1130 | |||
1131 | phd = (struct partitionHeaderDesc *)p->partitionContentsUse; | ||
1132 | if (phd->unallocSpaceTable.extLength) { | ||
1133 | kernel_lb_addr loc = { | ||
1134 | .logicalBlockNum = le32_to_cpu( | ||
1135 | phd->unallocSpaceTable.extPosition), | ||
1136 | .partitionReferenceNum = p_index, | ||
1137 | }; | ||
1138 | |||
1139 | map->s_uspace.s_table = udf_iget(sb, loc); | ||
1140 | if (!map->s_uspace.s_table) { | ||
1141 | udf_debug("cannot load unallocSpaceTable (part %d)\n", | ||
1142 | p_index); | ||
1143 | return 1; | ||
1144 | } | ||
1145 | map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE; | ||
1146 | udf_debug("unallocSpaceTable (part %d) @ %ld\n", | ||
1147 | p_index, map->s_uspace.s_table->i_ino); | ||
1148 | } | ||
1149 | |||
1150 | if (phd->unallocSpaceBitmap.extLength) { | ||
1151 | struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index); | ||
1152 | if (!bitmap) | ||
1153 | return 1; | ||
1154 | map->s_uspace.s_bitmap = bitmap; | ||
1155 | bitmap->s_extLength = le32_to_cpu( | ||
1156 | phd->unallocSpaceBitmap.extLength); | ||
1157 | bitmap->s_extPosition = le32_to_cpu( | ||
1158 | phd->unallocSpaceBitmap.extPosition); | ||
1159 | map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; | ||
1160 | udf_debug("unallocSpaceBitmap (part %d) @ %d\n", p_index, | ||
1161 | bitmap->s_extPosition); | ||
1162 | } | ||
1163 | |||
1164 | if (phd->partitionIntegrityTable.extLength) | ||
1165 | udf_debug("partitionIntegrityTable (part %d)\n", p_index); | ||
1166 | |||
1167 | if (phd->freedSpaceTable.extLength) { | ||
1168 | kernel_lb_addr loc = { | ||
1169 | .logicalBlockNum = le32_to_cpu( | ||
1170 | phd->freedSpaceTable.extPosition), | ||
1171 | .partitionReferenceNum = p_index, | ||
1172 | }; | ||
1173 | |||
1174 | map->s_fspace.s_table = udf_iget(sb, loc); | ||
1175 | if (!map->s_fspace.s_table) { | ||
1176 | udf_debug("cannot load freedSpaceTable (part %d)\n", | ||
1177 | p_index); | ||
1178 | return 1; | ||
1179 | } | ||
1180 | |||
1181 | map->s_partition_flags |= UDF_PART_FLAG_FREED_TABLE; | ||
1182 | udf_debug("freedSpaceTable (part %d) @ %ld\n", | ||
1183 | p_index, map->s_fspace.s_table->i_ino); | ||
1184 | } | ||
1185 | |||
1186 | if (phd->freedSpaceBitmap.extLength) { | ||
1187 | struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index); | ||
1188 | if (!bitmap) | ||
1189 | return 1; | ||
1190 | map->s_fspace.s_bitmap = bitmap; | ||
1191 | bitmap->s_extLength = le32_to_cpu( | ||
1192 | phd->freedSpaceBitmap.extLength); | ||
1193 | bitmap->s_extPosition = le32_to_cpu( | ||
1194 | phd->freedSpaceBitmap.extPosition); | ||
1195 | map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; | ||
1196 | udf_debug("freedSpaceBitmap (part %d) @ %d\n", p_index, | ||
1197 | bitmap->s_extPosition); | ||
1198 | } | ||
1199 | return 0; | ||
1200 | } | ||
1201 | |||
1202 | static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) | ||
1203 | { | ||
1204 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
1205 | struct udf_part_map *map = &sbi->s_partmaps[p_index]; | ||
1206 | kernel_lb_addr ino; | ||
1207 | struct buffer_head *bh = NULL; | ||
1208 | struct udf_inode_info *vati; | ||
1209 | uint32_t pos; | ||
1210 | struct virtualAllocationTable20 *vat20; | ||
1211 | |||
1212 | /* VAT file entry is in the last recorded block */ | ||
1213 | ino.partitionReferenceNum = type1_index; | ||
1214 | ino.logicalBlockNum = sbi->s_last_block - map->s_partition_root; | ||
1215 | sbi->s_vat_inode = udf_iget(sb, ino); | ||
1216 | if (!sbi->s_vat_inode) | ||
1217 | return 1; | ||
1218 | |||
1219 | if (map->s_partition_type == UDF_VIRTUAL_MAP15) { | ||
1220 | map->s_type_specific.s_virtual.s_start_offset = 0; | ||
1221 | map->s_type_specific.s_virtual.s_num_entries = | ||
1222 | (sbi->s_vat_inode->i_size - 36) >> 2; | ||
1223 | } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { | ||
1224 | vati = UDF_I(sbi->s_vat_inode); | ||
1225 | if (vati->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { | ||
1226 | pos = udf_block_map(sbi->s_vat_inode, 0); | ||
1227 | bh = sb_bread(sb, pos); | ||
1228 | if (!bh) | ||
1229 | return 1; | ||
1230 | vat20 = (struct virtualAllocationTable20 *)bh->b_data; | ||
1231 | } else { | ||
1232 | vat20 = (struct virtualAllocationTable20 *) | ||
1233 | vati->i_ext.i_data; | ||
1234 | } | ||
1235 | |||
1236 | map->s_type_specific.s_virtual.s_start_offset = | ||
1237 | le16_to_cpu(vat20->lengthHeader); | ||
1238 | map->s_type_specific.s_virtual.s_num_entries = | ||
1239 | (sbi->s_vat_inode->i_size - | ||
1240 | map->s_type_specific.s_virtual. | ||
1241 | s_start_offset) >> 2; | ||
1242 | brelse(bh); | ||
1243 | } | ||
1244 | return 0; | ||
1245 | } | ||
1246 | |||
1247 | static int udf_load_partdesc(struct super_block *sb, sector_t block) | ||
1063 | { | 1248 | { |
1249 | struct buffer_head *bh; | ||
1064 | struct partitionDesc *p; | 1250 | struct partitionDesc *p; |
1065 | int i; | ||
1066 | struct udf_part_map *map; | 1251 | struct udf_part_map *map; |
1067 | struct udf_sb_info *sbi; | 1252 | struct udf_sb_info *sbi = UDF_SB(sb); |
1253 | int i, type1_idx; | ||
1254 | uint16_t partitionNumber; | ||
1255 | uint16_t ident; | ||
1256 | int ret = 0; | ||
1257 | |||
1258 | bh = udf_read_tagged(sb, block, block, &ident); | ||
1259 | if (!bh) | ||
1260 | return 1; | ||
1261 | if (ident != TAG_IDENT_PD) | ||
1262 | goto out_bh; | ||
1068 | 1263 | ||
1069 | p = (struct partitionDesc *)bh->b_data; | 1264 | p = (struct partitionDesc *)bh->b_data; |
1070 | sbi = UDF_SB(sb); | 1265 | partitionNumber = le16_to_cpu(p->partitionNumber); |
1071 | 1266 | ||
1267 | /* First scan for TYPE1, SPARABLE and METADATA partitions */ | ||
1072 | for (i = 0; i < sbi->s_partitions; i++) { | 1268 | for (i = 0; i < sbi->s_partitions; i++) { |
1073 | map = &sbi->s_partmaps[i]; | 1269 | map = &sbi->s_partmaps[i]; |
1074 | udf_debug("Searching map: (%d == %d)\n", | 1270 | udf_debug("Searching map: (%d == %d)\n", |
1075 | map->s_partition_num, | 1271 | map->s_partition_num, partitionNumber); |
1076 | le16_to_cpu(p->partitionNumber)); | 1272 | if (map->s_partition_num == partitionNumber && |
1077 | if (map->s_partition_num == | 1273 | (map->s_partition_type == UDF_TYPE1_MAP15 || |
1078 | le16_to_cpu(p->partitionNumber)) { | 1274 | map->s_partition_type == UDF_SPARABLE_MAP15)) |
1079 | map->s_partition_len = | ||
1080 | le32_to_cpu(p->partitionLength); /* blocks */ | ||
1081 | map->s_partition_root = | ||
1082 | le32_to_cpu(p->partitionStartingLocation); | ||
1083 | if (p->accessType == | ||
1084 | cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY)) | ||
1085 | map->s_partition_flags |= | ||
1086 | UDF_PART_FLAG_READ_ONLY; | ||
1087 | if (p->accessType == | ||
1088 | cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE)) | ||
1089 | map->s_partition_flags |= | ||
1090 | UDF_PART_FLAG_WRITE_ONCE; | ||
1091 | if (p->accessType == | ||
1092 | cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE)) | ||
1093 | map->s_partition_flags |= | ||
1094 | UDF_PART_FLAG_REWRITABLE; | ||
1095 | if (p->accessType == | ||
1096 | cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE)) | ||
1097 | map->s_partition_flags |= | ||
1098 | UDF_PART_FLAG_OVERWRITABLE; | ||
1099 | |||
1100 | if (!strcmp(p->partitionContents.ident, | ||
1101 | PD_PARTITION_CONTENTS_NSR02) || | ||
1102 | !strcmp(p->partitionContents.ident, | ||
1103 | PD_PARTITION_CONTENTS_NSR03)) { | ||
1104 | struct partitionHeaderDesc *phd; | ||
1105 | |||
1106 | phd = (struct partitionHeaderDesc *) | ||
1107 | (p->partitionContentsUse); | ||
1108 | if (phd->unallocSpaceTable.extLength) { | ||
1109 | kernel_lb_addr loc = { | ||
1110 | .logicalBlockNum = le32_to_cpu(phd->unallocSpaceTable.extPosition), | ||
1111 | .partitionReferenceNum = i, | ||
1112 | }; | ||
1113 | |||
1114 | map->s_uspace.s_table = | ||
1115 | udf_iget(sb, loc); | ||
1116 | if (!map->s_uspace.s_table) { | ||
1117 | udf_debug("cannot load unallocSpaceTable (part %d)\n", i); | ||
1118 | return 1; | ||
1119 | } | ||
1120 | map->s_partition_flags |= | ||
1121 | UDF_PART_FLAG_UNALLOC_TABLE; | ||
1122 | udf_debug("unallocSpaceTable (part %d) @ %ld\n", | ||
1123 | i, map->s_uspace.s_table->i_ino); | ||
1124 | } | ||
1125 | if (phd->unallocSpaceBitmap.extLength) { | ||
1126 | struct udf_bitmap *bitmap = | ||
1127 | udf_sb_alloc_bitmap(sb, i); | ||
1128 | map->s_uspace.s_bitmap = bitmap; | ||
1129 | if (bitmap != NULL) { | ||
1130 | bitmap->s_extLength = | ||
1131 | le32_to_cpu(phd->unallocSpaceBitmap.extLength); | ||
1132 | bitmap->s_extPosition = | ||
1133 | le32_to_cpu(phd->unallocSpaceBitmap.extPosition); | ||
1134 | map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; | ||
1135 | udf_debug("unallocSpaceBitmap (part %d) @ %d\n", | ||
1136 | i, bitmap->s_extPosition); | ||
1137 | } | ||
1138 | } | ||
1139 | if (phd->partitionIntegrityTable.extLength) | ||
1140 | udf_debug("partitionIntegrityTable (part %d)\n", i); | ||
1141 | if (phd->freedSpaceTable.extLength) { | ||
1142 | kernel_lb_addr loc = { | ||
1143 | .logicalBlockNum = le32_to_cpu(phd->freedSpaceTable.extPosition), | ||
1144 | .partitionReferenceNum = i, | ||
1145 | }; | ||
1146 | |||
1147 | map->s_fspace.s_table = | ||
1148 | udf_iget(sb, loc); | ||
1149 | if (!map->s_fspace.s_table) { | ||
1150 | udf_debug("cannot load freedSpaceTable (part %d)\n", i); | ||
1151 | return 1; | ||
1152 | } | ||
1153 | map->s_partition_flags |= | ||
1154 | UDF_PART_FLAG_FREED_TABLE; | ||
1155 | udf_debug("freedSpaceTable (part %d) @ %ld\n", | ||
1156 | i, map->s_fspace.s_table->i_ino); | ||
1157 | } | ||
1158 | if (phd->freedSpaceBitmap.extLength) { | ||
1159 | struct udf_bitmap *bitmap = | ||
1160 | udf_sb_alloc_bitmap(sb, i); | ||
1161 | map->s_fspace.s_bitmap = bitmap; | ||
1162 | if (bitmap != NULL) { | ||
1163 | bitmap->s_extLength = | ||
1164 | le32_to_cpu(phd->freedSpaceBitmap.extLength); | ||
1165 | bitmap->s_extPosition = | ||
1166 | le32_to_cpu(phd->freedSpaceBitmap.extPosition); | ||
1167 | map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; | ||
1168 | udf_debug("freedSpaceBitmap (part %d) @ %d\n", | ||
1169 | i, bitmap->s_extPosition); | ||
1170 | } | ||
1171 | } | ||
1172 | } | ||
1173 | break; | 1275 | break; |
1174 | } | ||
1175 | } | 1276 | } |
1176 | if (i == sbi->s_partitions) | 1277 | |
1278 | if (i >= sbi->s_partitions) { | ||
1177 | udf_debug("Partition (%d) not found in partition map\n", | 1279 | udf_debug("Partition (%d) not found in partition map\n", |
1178 | le16_to_cpu(p->partitionNumber)); | 1280 | partitionNumber); |
1179 | else | 1281 | goto out_bh; |
1180 | udf_debug("Partition (%d:%d type %x) starts at physical %d, " | 1282 | } |
1181 | "block length %d\n", | 1283 | |
1182 | le16_to_cpu(p->partitionNumber), i, | 1284 | ret = udf_fill_partdesc_info(sb, p, i); |
1183 | map->s_partition_type, | 1285 | |
1184 | map->s_partition_root, | 1286 | /* |
1185 | map->s_partition_len); | 1287 | * Now rescan for VIRTUAL or METADATA partitions when SPARABLE and |
1186 | return 0; | 1288 | * PHYSICAL partitions are already set up |
1289 | */ | ||
1290 | type1_idx = i; | ||
1291 | for (i = 0; i < sbi->s_partitions; i++) { | ||
1292 | map = &sbi->s_partmaps[i]; | ||
1293 | |||
1294 | if (map->s_partition_num == partitionNumber && | ||
1295 | (map->s_partition_type == UDF_VIRTUAL_MAP15 || | ||
1296 | map->s_partition_type == UDF_VIRTUAL_MAP20 || | ||
1297 | map->s_partition_type == UDF_METADATA_MAP25)) | ||
1298 | break; | ||
1299 | } | ||
1300 | |||
1301 | if (i >= sbi->s_partitions) | ||
1302 | goto out_bh; | ||
1303 | |||
1304 | ret = udf_fill_partdesc_info(sb, p, i); | ||
1305 | if (ret) | ||
1306 | goto out_bh; | ||
1307 | |||
1308 | if (map->s_partition_type == UDF_METADATA_MAP25) { | ||
1309 | ret = udf_load_metadata_files(sb, i); | ||
1310 | if (ret) { | ||
1311 | printk(KERN_ERR "UDF-fs: error loading MetaData " | ||
1312 | "partition map %d\n", i); | ||
1313 | goto out_bh; | ||
1314 | } | ||
1315 | } else { | ||
1316 | ret = udf_load_vat(sb, i, type1_idx); | ||
1317 | if (ret) | ||
1318 | goto out_bh; | ||
1319 | /* | ||
1320 | * Mark filesystem read-only if we have a partition with | ||
1321 | * virtual map since we don't handle writing to it (we | ||
1322 | * overwrite blocks instead of relocating them). | ||
1323 | */ | ||
1324 | sb->s_flags |= MS_RDONLY; | ||
1325 | printk(KERN_NOTICE "UDF-fs: Filesystem marked read-only " | ||
1326 | "because writing to pseudooverwrite partition is " | ||
1327 | "not implemented.\n"); | ||
1328 | } | ||
1329 | out_bh: | ||
1330 | /* In case loading failed, we handle cleanup in udf_fill_super */ | ||
1331 | brelse(bh); | ||
1332 | return ret; | ||
1187 | } | 1333 | } |
1188 | 1334 | ||
1189 | static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, | 1335 | static int udf_load_logicalvol(struct super_block *sb, sector_t block, |
1190 | kernel_lb_addr *fileset) | 1336 | kernel_lb_addr *fileset) |
1191 | { | 1337 | { |
1192 | struct logicalVolDesc *lvd; | 1338 | struct logicalVolDesc *lvd; |
@@ -1194,12 +1340,21 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, | |||
1194 | uint8_t type; | 1340 | uint8_t type; |
1195 | struct udf_sb_info *sbi = UDF_SB(sb); | 1341 | struct udf_sb_info *sbi = UDF_SB(sb); |
1196 | struct genericPartitionMap *gpm; | 1342 | struct genericPartitionMap *gpm; |
1343 | uint16_t ident; | ||
1344 | struct buffer_head *bh; | ||
1345 | int ret = 0; | ||
1197 | 1346 | ||
1347 | bh = udf_read_tagged(sb, block, block, &ident); | ||
1348 | if (!bh) | ||
1349 | return 1; | ||
1350 | BUG_ON(ident != TAG_IDENT_LVD); | ||
1198 | lvd = (struct logicalVolDesc *)bh->b_data; | 1351 | lvd = (struct logicalVolDesc *)bh->b_data; |
1199 | 1352 | ||
1200 | i = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); | 1353 | i = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); |
1201 | if (i != 0) | 1354 | if (i != 0) { |
1202 | return i; | 1355 | ret = i; |
1356 | goto out_bh; | ||
1357 | } | ||
1203 | 1358 | ||
1204 | for (i = 0, offset = 0; | 1359 | for (i = 0, offset = 0; |
1205 | i < sbi->s_partitions && offset < le32_to_cpu(lvd->mapTableLength); | 1360 | i < sbi->s_partitions && offset < le32_to_cpu(lvd->mapTableLength); |
@@ -1223,12 +1378,12 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, | |||
1223 | u16 suf = | 1378 | u16 suf = |
1224 | le16_to_cpu(((__le16 *)upm2->partIdent. | 1379 | le16_to_cpu(((__le16 *)upm2->partIdent. |
1225 | identSuffix)[0]); | 1380 | identSuffix)[0]); |
1226 | if (suf == 0x0150) { | 1381 | if (suf < 0x0200) { |
1227 | map->s_partition_type = | 1382 | map->s_partition_type = |
1228 | UDF_VIRTUAL_MAP15; | 1383 | UDF_VIRTUAL_MAP15; |
1229 | map->s_partition_func = | 1384 | map->s_partition_func = |
1230 | udf_get_pblock_virt15; | 1385 | udf_get_pblock_virt15; |
1231 | } else if (suf == 0x0200) { | 1386 | } else { |
1232 | map->s_partition_type = | 1387 | map->s_partition_type = |
1233 | UDF_VIRTUAL_MAP20; | 1388 | UDF_VIRTUAL_MAP20; |
1234 | map->s_partition_func = | 1389 | map->s_partition_func = |
@@ -1238,7 +1393,6 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, | |||
1238 | UDF_ID_SPARABLE, | 1393 | UDF_ID_SPARABLE, |
1239 | strlen(UDF_ID_SPARABLE))) { | 1394 | strlen(UDF_ID_SPARABLE))) { |
1240 | uint32_t loc; | 1395 | uint32_t loc; |
1241 | uint16_t ident; | ||
1242 | struct sparingTable *st; | 1396 | struct sparingTable *st; |
1243 | struct sparablePartitionMap *spm = | 1397 | struct sparablePartitionMap *spm = |
1244 | (struct sparablePartitionMap *)gpm; | 1398 | (struct sparablePartitionMap *)gpm; |
@@ -1256,22 +1410,64 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, | |||
1256 | map->s_type_specific.s_sparing. | 1410 | map->s_type_specific.s_sparing. |
1257 | s_spar_map[j] = bh2; | 1411 | s_spar_map[j] = bh2; |
1258 | 1412 | ||
1259 | if (bh2 != NULL) { | 1413 | if (bh2 == NULL) |
1260 | st = (struct sparingTable *) | 1414 | continue; |
1261 | bh2->b_data; | 1415 | |
1262 | if (ident != 0 || strncmp( | 1416 | st = (struct sparingTable *)bh2->b_data; |
1263 | st->sparingIdent.ident, | 1417 | if (ident != 0 || strncmp( |
1264 | UDF_ID_SPARING, | 1418 | st->sparingIdent.ident, |
1265 | strlen(UDF_ID_SPARING))) { | 1419 | UDF_ID_SPARING, |
1266 | brelse(bh2); | 1420 | strlen(UDF_ID_SPARING))) { |
1267 | map->s_type_specific. | 1421 | brelse(bh2); |
1268 | s_sparing. | 1422 | map->s_type_specific.s_sparing. |
1269 | s_spar_map[j] = | 1423 | s_spar_map[j] = NULL; |
1270 | NULL; | ||
1271 | } | ||
1272 | } | 1424 | } |
1273 | } | 1425 | } |
1274 | map->s_partition_func = udf_get_pblock_spar15; | 1426 | map->s_partition_func = udf_get_pblock_spar15; |
1427 | } else if (!strncmp(upm2->partIdent.ident, | ||
1428 | UDF_ID_METADATA, | ||
1429 | strlen(UDF_ID_METADATA))) { | ||
1430 | struct udf_meta_data *mdata = | ||
1431 | &map->s_type_specific.s_metadata; | ||
1432 | struct metadataPartitionMap *mdm = | ||
1433 | (struct metadataPartitionMap *) | ||
1434 | &(lvd->partitionMaps[offset]); | ||
1435 | udf_debug("Parsing Logical vol part %d " | ||
1436 | "type %d id=%s\n", i, type, | ||
1437 | UDF_ID_METADATA); | ||
1438 | |||
1439 | map->s_partition_type = UDF_METADATA_MAP25; | ||
1440 | map->s_partition_func = udf_get_pblock_meta25; | ||
1441 | |||
1442 | mdata->s_meta_file_loc = | ||
1443 | le32_to_cpu(mdm->metadataFileLoc); | ||
1444 | mdata->s_mirror_file_loc = | ||
1445 | le32_to_cpu(mdm->metadataMirrorFileLoc); | ||
1446 | mdata->s_bitmap_file_loc = | ||
1447 | le32_to_cpu(mdm->metadataBitmapFileLoc); | ||
1448 | mdata->s_alloc_unit_size = | ||
1449 | le32_to_cpu(mdm->allocUnitSize); | ||
1450 | mdata->s_align_unit_size = | ||
1451 | le16_to_cpu(mdm->alignUnitSize); | ||
1452 | mdata->s_dup_md_flag = | ||
1453 | mdm->flags & 0x01; | ||
1454 | |||
1455 | udf_debug("Metadata Ident suffix=0x%x\n", | ||
1456 | (le16_to_cpu( | ||
1457 | ((__le16 *) | ||
1458 | mdm->partIdent.identSuffix)[0]))); | ||
1459 | udf_debug("Metadata part num=%d\n", | ||
1460 | le16_to_cpu(mdm->partitionNum)); | ||
1461 | udf_debug("Metadata part alloc unit size=%d\n", | ||
1462 | le32_to_cpu(mdm->allocUnitSize)); | ||
1463 | udf_debug("Metadata file loc=%d\n", | ||
1464 | le32_to_cpu(mdm->metadataFileLoc)); | ||
1465 | udf_debug("Mirror file loc=%d\n", | ||
1466 | le32_to_cpu(mdm->metadataMirrorFileLoc)); | ||
1467 | udf_debug("Bitmap file loc=%d\n", | ||
1468 | le32_to_cpu(mdm->metadataBitmapFileLoc)); | ||
1469 | udf_debug("Duplicate Flag: %d %d\n", | ||
1470 | mdata->s_dup_md_flag, mdm->flags); | ||
1275 | } else { | 1471 | } else { |
1276 | udf_debug("Unknown ident: %s\n", | 1472 | udf_debug("Unknown ident: %s\n", |
1277 | upm2->partIdent.ident); | 1473 | upm2->partIdent.ident); |
@@ -1296,7 +1492,9 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, | |||
1296 | if (lvd->integritySeqExt.extLength) | 1492 | if (lvd->integritySeqExt.extLength) |
1297 | udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt)); | 1493 | udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt)); |
1298 | 1494 | ||
1299 | return 0; | 1495 | out_bh: |
1496 | brelse(bh); | ||
1497 | return ret; | ||
1300 | } | 1498 | } |
1301 | 1499 | ||
1302 | /* | 1500 | /* |
@@ -1345,7 +1543,7 @@ static void udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc) | |||
1345 | * July 1, 1997 - Andrew E. Mileski | 1543 | * July 1, 1997 - Andrew E. Mileski |
1346 | * Written, tested, and released. | 1544 | * Written, tested, and released. |
1347 | */ | 1545 | */ |
1348 | static int udf_process_sequence(struct super_block *sb, long block, | 1546 | static noinline int udf_process_sequence(struct super_block *sb, long block, |
1349 | long lastblock, kernel_lb_addr *fileset) | 1547 | long lastblock, kernel_lb_addr *fileset) |
1350 | { | 1548 | { |
1351 | struct buffer_head *bh = NULL; | 1549 | struct buffer_head *bh = NULL; |
@@ -1354,19 +1552,25 @@ static int udf_process_sequence(struct super_block *sb, long block, | |||
1354 | struct generic_desc *gd; | 1552 | struct generic_desc *gd; |
1355 | struct volDescPtr *vdp; | 1553 | struct volDescPtr *vdp; |
1356 | int done = 0; | 1554 | int done = 0; |
1357 | int i, j; | ||
1358 | uint32_t vdsn; | 1555 | uint32_t vdsn; |
1359 | uint16_t ident; | 1556 | uint16_t ident; |
1360 | long next_s = 0, next_e = 0; | 1557 | long next_s = 0, next_e = 0; |
1361 | 1558 | ||
1362 | memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); | 1559 | memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); |
1363 | 1560 | ||
1364 | /* Read the main descriptor sequence */ | 1561 | /* |
1562 | * Read the main descriptor sequence and find which descriptors | ||
1563 | * are in it. | ||
1564 | */ | ||
1365 | for (; (!done && block <= lastblock); block++) { | 1565 | for (; (!done && block <= lastblock); block++) { |
1366 | 1566 | ||
1367 | bh = udf_read_tagged(sb, block, block, &ident); | 1567 | bh = udf_read_tagged(sb, block, block, &ident); |
1368 | if (!bh) | 1568 | if (!bh) { |
1369 | break; | 1569 | printk(KERN_ERR "udf: Block %Lu of volume descriptor " |
1570 | "sequence is corrupted or we could not read " | ||
1571 | "it.\n", (unsigned long long)block); | ||
1572 | return 1; | ||
1573 | } | ||
1370 | 1574 | ||
1371 | /* Process each descriptor (ISO 13346 3/8.3-8.4) */ | 1575 | /* Process each descriptor (ISO 13346 3/8.3-8.4) */ |
1372 | gd = (struct generic_desc *)bh->b_data; | 1576 | gd = (struct generic_desc *)bh->b_data; |
@@ -1432,41 +1636,31 @@ static int udf_process_sequence(struct super_block *sb, long block, | |||
1432 | } | 1636 | } |
1433 | brelse(bh); | 1637 | brelse(bh); |
1434 | } | 1638 | } |
1435 | for (i = 0; i < VDS_POS_LENGTH; i++) { | 1639 | /* |
1436 | if (vds[i].block) { | 1640 | * Now read interesting descriptors again and process them |
1437 | bh = udf_read_tagged(sb, vds[i].block, vds[i].block, | 1641 | * in a suitable order |
1438 | &ident); | 1642 | */ |
1439 | 1643 | if (!vds[VDS_POS_PRIMARY_VOL_DESC].block) { | |
1440 | if (i == VDS_POS_PRIMARY_VOL_DESC) { | 1644 | printk(KERN_ERR "udf: Primary Volume Descriptor not found!\n"); |
1441 | udf_load_pvoldesc(sb, bh); | 1645 | return 1; |
1442 | } else if (i == VDS_POS_LOGICAL_VOL_DESC) { | 1646 | } |
1443 | if (udf_load_logicalvol(sb, bh, fileset)) { | 1647 | if (udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block)) |
1444 | brelse(bh); | 1648 | return 1; |
1445 | return 1; | 1649 | |
1446 | } | 1650 | if (vds[VDS_POS_LOGICAL_VOL_DESC].block && udf_load_logicalvol(sb, |
1447 | } else if (i == VDS_POS_PARTITION_DESC) { | 1651 | vds[VDS_POS_LOGICAL_VOL_DESC].block, fileset)) |
1448 | struct buffer_head *bh2 = NULL; | 1652 | return 1; |
1449 | if (udf_load_partdesc(sb, bh)) { | 1653 | |
1450 | brelse(bh); | 1654 | if (vds[VDS_POS_PARTITION_DESC].block) { |
1451 | return 1; | 1655 | /* |
1452 | } | 1656 | * We rescan the whole descriptor sequence to find |
1453 | for (j = vds[i].block + 1; | 1657 | * partition descriptor blocks and process them. |
1454 | j < vds[VDS_POS_TERMINATING_DESC].block; | 1658 | */ |
1455 | j++) { | 1659 | for (block = vds[VDS_POS_PARTITION_DESC].block; |
1456 | bh2 = udf_read_tagged(sb, j, j, &ident); | 1660 | block < vds[VDS_POS_TERMINATING_DESC].block; |
1457 | gd = (struct generic_desc *)bh2->b_data; | 1661 | block++) |
1458 | if (ident == TAG_IDENT_PD) | 1662 | if (udf_load_partdesc(sb, block)) |
1459 | if (udf_load_partdesc(sb, | 1663 | return 1; |
1460 | bh2)) { | ||
1461 | brelse(bh); | ||
1462 | brelse(bh2); | ||
1463 | return 1; | ||
1464 | } | ||
1465 | brelse(bh2); | ||
1466 | } | ||
1467 | } | ||
1468 | brelse(bh); | ||
1469 | } | ||
1470 | } | 1664 | } |
1471 | 1665 | ||
1472 | return 0; | 1666 | return 0; |
@@ -1478,6 +1672,7 @@ static int udf_process_sequence(struct super_block *sb, long block, | |||
1478 | static int udf_check_valid(struct super_block *sb, int novrs, int silent) | 1672 | static int udf_check_valid(struct super_block *sb, int novrs, int silent) |
1479 | { | 1673 | { |
1480 | long block; | 1674 | long block; |
1675 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
1481 | 1676 | ||
1482 | if (novrs) { | 1677 | if (novrs) { |
1483 | udf_debug("Validity check skipped because of novrs option\n"); | 1678 | udf_debug("Validity check skipped because of novrs option\n"); |
@@ -1485,27 +1680,22 @@ static int udf_check_valid(struct super_block *sb, int novrs, int silent) | |||
1485 | } | 1680 | } |
1486 | /* Check that it is NSR02 compliant */ | 1681 | /* Check that it is NSR02 compliant */ |
1487 | /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */ | 1682 | /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */ |
1488 | else { | 1683 | block = udf_vrs(sb, silent); |
1489 | block = udf_vrs(sb, silent); | 1684 | if (block == -1) |
1490 | if (block == -1) { | 1685 | udf_debug("Failed to read byte 32768. Assuming open " |
1491 | struct udf_sb_info *sbi = UDF_SB(sb); | 1686 | "disc. Skipping validity check\n"); |
1492 | udf_debug("Failed to read byte 32768. Assuming open " | 1687 | if (block && !sbi->s_last_block) |
1493 | "disc. Skipping validity check\n"); | 1688 | sbi->s_last_block = udf_get_last_block(sb); |
1494 | if (!sbi->s_last_block) | 1689 | return !block; |
1495 | sbi->s_last_block = udf_get_last_block(sb); | ||
1496 | return 0; | ||
1497 | } else | ||
1498 | return !block; | ||
1499 | } | ||
1500 | } | 1690 | } |
1501 | 1691 | ||
1502 | static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) | 1692 | static int udf_load_sequence(struct super_block *sb, kernel_lb_addr *fileset) |
1503 | { | 1693 | { |
1504 | struct anchorVolDescPtr *anchor; | 1694 | struct anchorVolDescPtr *anchor; |
1505 | uint16_t ident; | 1695 | uint16_t ident; |
1506 | struct buffer_head *bh; | 1696 | struct buffer_head *bh; |
1507 | long main_s, main_e, reserve_s, reserve_e; | 1697 | long main_s, main_e, reserve_s, reserve_e; |
1508 | int i, j; | 1698 | int i; |
1509 | struct udf_sb_info *sbi; | 1699 | struct udf_sb_info *sbi; |
1510 | 1700 | ||
1511 | if (!sb) | 1701 | if (!sb) |
@@ -1515,6 +1705,7 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) | |||
1515 | for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { | 1705 | for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { |
1516 | if (!sbi->s_anchor[i]) | 1706 | if (!sbi->s_anchor[i]) |
1517 | continue; | 1707 | continue; |
1708 | |||
1518 | bh = udf_read_tagged(sb, sbi->s_anchor[i], sbi->s_anchor[i], | 1709 | bh = udf_read_tagged(sb, sbi->s_anchor[i], sbi->s_anchor[i], |
1519 | &ident); | 1710 | &ident); |
1520 | if (!bh) | 1711 | if (!bh) |
@@ -1553,76 +1744,6 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) | |||
1553 | } | 1744 | } |
1554 | udf_debug("Using anchor in block %d\n", sbi->s_anchor[i]); | 1745 | udf_debug("Using anchor in block %d\n", sbi->s_anchor[i]); |
1555 | 1746 | ||
1556 | for (i = 0; i < sbi->s_partitions; i++) { | ||
1557 | kernel_lb_addr uninitialized_var(ino); | ||
1558 | struct udf_part_map *map = &sbi->s_partmaps[i]; | ||
1559 | switch (map->s_partition_type) { | ||
1560 | case UDF_VIRTUAL_MAP15: | ||
1561 | case UDF_VIRTUAL_MAP20: | ||
1562 | if (!sbi->s_last_block) { | ||
1563 | sbi->s_last_block = udf_get_last_block(sb); | ||
1564 | udf_find_anchor(sb); | ||
1565 | } | ||
1566 | |||
1567 | if (!sbi->s_last_block) { | ||
1568 | udf_debug("Unable to determine Lastblock (For " | ||
1569 | "Virtual Partition)\n"); | ||
1570 | return 1; | ||
1571 | } | ||
1572 | |||
1573 | for (j = 0; j < sbi->s_partitions; j++) { | ||
1574 | struct udf_part_map *map2 = &sbi->s_partmaps[j]; | ||
1575 | if (j != i && | ||
1576 | map->s_volumeseqnum == | ||
1577 | map2->s_volumeseqnum && | ||
1578 | map->s_partition_num == | ||
1579 | map2->s_partition_num) { | ||
1580 | ino.partitionReferenceNum = j; | ||
1581 | ino.logicalBlockNum = | ||
1582 | sbi->s_last_block - | ||
1583 | map2->s_partition_root; | ||
1584 | break; | ||
1585 | } | ||
1586 | } | ||
1587 | |||
1588 | if (j == sbi->s_partitions) | ||
1589 | return 1; | ||
1590 | |||
1591 | sbi->s_vat_inode = udf_iget(sb, ino); | ||
1592 | if (!sbi->s_vat_inode) | ||
1593 | return 1; | ||
1594 | |||
1595 | if (map->s_partition_type == UDF_VIRTUAL_MAP15) { | ||
1596 | map->s_type_specific.s_virtual.s_start_offset = | ||
1597 | udf_ext0_offset(sbi->s_vat_inode); | ||
1598 | map->s_type_specific.s_virtual.s_num_entries = | ||
1599 | (sbi->s_vat_inode->i_size - 36) >> 2; | ||
1600 | } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { | ||
1601 | uint32_t pos; | ||
1602 | struct virtualAllocationTable20 *vat20; | ||
1603 | |||
1604 | pos = udf_block_map(sbi->s_vat_inode, 0); | ||
1605 | bh = sb_bread(sb, pos); | ||
1606 | if (!bh) | ||
1607 | return 1; | ||
1608 | vat20 = (struct virtualAllocationTable20 *) | ||
1609 | bh->b_data + | ||
1610 | udf_ext0_offset(sbi->s_vat_inode); | ||
1611 | map->s_type_specific.s_virtual.s_start_offset = | ||
1612 | le16_to_cpu(vat20->lengthHeader) + | ||
1613 | udf_ext0_offset(sbi->s_vat_inode); | ||
1614 | map->s_type_specific.s_virtual.s_num_entries = | ||
1615 | (sbi->s_vat_inode->i_size - | ||
1616 | map->s_type_specific.s_virtual. | ||
1617 | s_start_offset) >> 2; | ||
1618 | brelse(bh); | ||
1619 | } | ||
1620 | map->s_partition_root = udf_get_pblock(sb, 0, i, 0); | ||
1621 | map->s_partition_len = | ||
1622 | sbi->s_partmaps[ino.partitionReferenceNum]. | ||
1623 | s_partition_len; | ||
1624 | } | ||
1625 | } | ||
1626 | return 0; | 1747 | return 0; |
1627 | } | 1748 | } |
1628 | 1749 | ||
@@ -1630,65 +1751,61 @@ static void udf_open_lvid(struct super_block *sb) | |||
1630 | { | 1751 | { |
1631 | struct udf_sb_info *sbi = UDF_SB(sb); | 1752 | struct udf_sb_info *sbi = UDF_SB(sb); |
1632 | struct buffer_head *bh = sbi->s_lvid_bh; | 1753 | struct buffer_head *bh = sbi->s_lvid_bh; |
1633 | if (bh) { | 1754 | struct logicalVolIntegrityDesc *lvid; |
1634 | kernel_timestamp cpu_time; | 1755 | struct logicalVolIntegrityDescImpUse *lvidiu; |
1635 | struct logicalVolIntegrityDesc *lvid = | 1756 | if (!bh) |
1636 | (struct logicalVolIntegrityDesc *)bh->b_data; | 1757 | return; |
1637 | struct logicalVolIntegrityDescImpUse *lvidiu = | ||
1638 | udf_sb_lvidiu(sbi); | ||
1639 | 1758 | ||
1640 | lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; | 1759 | lvid = (struct logicalVolIntegrityDesc *)bh->b_data; |
1641 | lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; | 1760 | lvidiu = udf_sb_lvidiu(sbi); |
1642 | if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) | ||
1643 | lvid->recordingDateAndTime = cpu_to_lets(cpu_time); | ||
1644 | lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN; | ||
1645 | 1761 | ||
1646 | lvid->descTag.descCRC = cpu_to_le16( | 1762 | lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; |
1647 | udf_crc((char *)lvid + sizeof(tag), | 1763 | lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; |
1648 | le16_to_cpu(lvid->descTag.descCRCLength), | 1764 | udf_time_to_disk_stamp(&lvid->recordingDateAndTime, |
1649 | 0)); | 1765 | CURRENT_TIME); |
1766 | lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN; | ||
1650 | 1767 | ||
1651 | lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); | 1768 | lvid->descTag.descCRC = cpu_to_le16( |
1652 | mark_buffer_dirty(bh); | 1769 | crc_itu_t(0, (char *)lvid + sizeof(tag), |
1653 | } | 1770 | le16_to_cpu(lvid->descTag.descCRCLength))); |
1771 | |||
1772 | lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); | ||
1773 | mark_buffer_dirty(bh); | ||
1654 | } | 1774 | } |
1655 | 1775 | ||
1656 | static void udf_close_lvid(struct super_block *sb) | 1776 | static void udf_close_lvid(struct super_block *sb) |
1657 | { | 1777 | { |
1658 | kernel_timestamp cpu_time; | ||
1659 | struct udf_sb_info *sbi = UDF_SB(sb); | 1778 | struct udf_sb_info *sbi = UDF_SB(sb); |
1660 | struct buffer_head *bh = sbi->s_lvid_bh; | 1779 | struct buffer_head *bh = sbi->s_lvid_bh; |
1661 | struct logicalVolIntegrityDesc *lvid; | 1780 | struct logicalVolIntegrityDesc *lvid; |
1781 | struct logicalVolIntegrityDescImpUse *lvidiu; | ||
1662 | 1782 | ||
1663 | if (!bh) | 1783 | if (!bh) |
1664 | return; | 1784 | return; |
1665 | 1785 | ||
1666 | lvid = (struct logicalVolIntegrityDesc *)bh->b_data; | 1786 | lvid = (struct logicalVolIntegrityDesc *)bh->b_data; |
1667 | 1787 | ||
1668 | if (lvid->integrityType == LVID_INTEGRITY_TYPE_OPEN) { | 1788 | if (lvid->integrityType != LVID_INTEGRITY_TYPE_OPEN) |
1669 | struct logicalVolIntegrityDescImpUse *lvidiu = | 1789 | return; |
1670 | udf_sb_lvidiu(sbi); | 1790 | |
1671 | lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; | 1791 | lvidiu = udf_sb_lvidiu(sbi); |
1672 | lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; | 1792 | lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; |
1673 | if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) | 1793 | lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; |
1674 | lvid->recordingDateAndTime = cpu_to_lets(cpu_time); | 1794 | udf_time_to_disk_stamp(&lvid->recordingDateAndTime, CURRENT_TIME); |
1675 | if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev)) | 1795 | if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev)) |
1676 | lvidiu->maxUDFWriteRev = | 1796 | lvidiu->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION); |
1677 | cpu_to_le16(UDF_MAX_WRITE_VERSION); | 1797 | if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev)) |
1678 | if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev)) | 1798 | lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev); |
1679 | lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev); | 1799 | if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev)) |
1680 | if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev)) | 1800 | lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev); |
1681 | lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev); | 1801 | lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); |
1682 | lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); | 1802 | |
1683 | 1803 | lvid->descTag.descCRC = cpu_to_le16( | |
1684 | lvid->descTag.descCRC = cpu_to_le16( | 1804 | crc_itu_t(0, (char *)lvid + sizeof(tag), |
1685 | udf_crc((char *)lvid + sizeof(tag), | 1805 | le16_to_cpu(lvid->descTag.descCRCLength))); |
1686 | le16_to_cpu(lvid->descTag.descCRCLength), | 1806 | |
1687 | 0)); | 1807 | lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); |
1688 | 1808 | mark_buffer_dirty(bh); | |
1689 | lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); | ||
1690 | mark_buffer_dirty(bh); | ||
1691 | } | ||
1692 | } | 1809 | } |
1693 | 1810 | ||
1694 | static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) | 1811 | static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) |
@@ -1708,22 +1825,35 @@ static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) | |||
1708 | vfree(bitmap); | 1825 | vfree(bitmap); |
1709 | } | 1826 | } |
1710 | 1827 | ||
1711 | /* | 1828 | static void udf_free_partition(struct udf_part_map *map) |
1712 | * udf_read_super | 1829 | { |
1713 | * | 1830 | int i; |
1714 | * PURPOSE | 1831 | struct udf_meta_data *mdata; |
1715 | * Complete the specified super block. | 1832 | |
1716 | * | 1833 | if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) |
1717 | * PRE-CONDITIONS | 1834 | iput(map->s_uspace.s_table); |
1718 | * sb Pointer to superblock to complete - never NULL. | 1835 | if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) |
1719 | * sb->s_dev Device to read suberblock from. | 1836 | iput(map->s_fspace.s_table); |
1720 | * options Pointer to mount options. | 1837 | if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) |
1721 | * silent Silent flag. | 1838 | udf_sb_free_bitmap(map->s_uspace.s_bitmap); |
1722 | * | 1839 | if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) |
1723 | * HISTORY | 1840 | udf_sb_free_bitmap(map->s_fspace.s_bitmap); |
1724 | * July 1, 1997 - Andrew E. Mileski | 1841 | if (map->s_partition_type == UDF_SPARABLE_MAP15) |
1725 | * Written, tested, and released. | 1842 | for (i = 0; i < 4; i++) |
1726 | */ | 1843 | brelse(map->s_type_specific.s_sparing.s_spar_map[i]); |
1844 | else if (map->s_partition_type == UDF_METADATA_MAP25) { | ||
1845 | mdata = &map->s_type_specific.s_metadata; | ||
1846 | iput(mdata->s_metadata_fe); | ||
1847 | mdata->s_metadata_fe = NULL; | ||
1848 | |||
1849 | iput(mdata->s_mirror_fe); | ||
1850 | mdata->s_mirror_fe = NULL; | ||
1851 | |||
1852 | iput(mdata->s_bitmap_fe); | ||
1853 | mdata->s_bitmap_fe = NULL; | ||
1854 | } | ||
1855 | } | ||
1856 | |||
1727 | static int udf_fill_super(struct super_block *sb, void *options, int silent) | 1857 | static int udf_fill_super(struct super_block *sb, void *options, int silent) |
1728 | { | 1858 | { |
1729 | int i; | 1859 | int i; |
@@ -1776,8 +1906,11 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) | |||
1776 | sbi->s_nls_map = uopt.nls_map; | 1906 | sbi->s_nls_map = uopt.nls_map; |
1777 | 1907 | ||
1778 | /* Set the block size for all transfers */ | 1908 | /* Set the block size for all transfers */ |
1779 | if (!udf_set_blocksize(sb, uopt.blocksize)) | 1909 | if (!sb_min_blocksize(sb, uopt.blocksize)) { |
1910 | udf_debug("Bad block size (%d)\n", uopt.blocksize); | ||
1911 | printk(KERN_ERR "udf: bad block size (%d)\n", uopt.blocksize); | ||
1780 | goto error_out; | 1912 | goto error_out; |
1913 | } | ||
1781 | 1914 | ||
1782 | if (uopt.session == 0xFFFFFFFF) | 1915 | if (uopt.session == 0xFFFFFFFF) |
1783 | sbi->s_session = udf_get_last_session(sb); | 1916 | sbi->s_session = udf_get_last_session(sb); |
@@ -1789,7 +1922,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) | |||
1789 | sbi->s_last_block = uopt.lastblock; | 1922 | sbi->s_last_block = uopt.lastblock; |
1790 | sbi->s_anchor[0] = sbi->s_anchor[1] = 0; | 1923 | sbi->s_anchor[0] = sbi->s_anchor[1] = 0; |
1791 | sbi->s_anchor[2] = uopt.anchor; | 1924 | sbi->s_anchor[2] = uopt.anchor; |
1792 | sbi->s_anchor[3] = 256; | ||
1793 | 1925 | ||
1794 | if (udf_check_valid(sb, uopt.novrs, silent)) { | 1926 | if (udf_check_valid(sb, uopt.novrs, silent)) { |
1795 | /* read volume recognition sequences */ | 1927 | /* read volume recognition sequences */ |
@@ -1806,7 +1938,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) | |||
1806 | sb->s_magic = UDF_SUPER_MAGIC; | 1938 | sb->s_magic = UDF_SUPER_MAGIC; |
1807 | sb->s_time_gran = 1000; | 1939 | sb->s_time_gran = 1000; |
1808 | 1940 | ||
1809 | if (udf_load_partition(sb, &fileset)) { | 1941 | if (udf_load_sequence(sb, &fileset)) { |
1810 | printk(KERN_WARNING "UDF-fs: No partition found (1)\n"); | 1942 | printk(KERN_WARNING "UDF-fs: No partition found (1)\n"); |
1811 | goto error_out; | 1943 | goto error_out; |
1812 | } | 1944 | } |
@@ -1856,12 +1988,12 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) | |||
1856 | } | 1988 | } |
1857 | 1989 | ||
1858 | if (!silent) { | 1990 | if (!silent) { |
1859 | kernel_timestamp ts; | 1991 | timestamp ts; |
1860 | udf_time_to_stamp(&ts, sbi->s_record_time); | 1992 | udf_time_to_disk_stamp(&ts, sbi->s_record_time); |
1861 | udf_info("UDF: Mounting volume '%s', " | 1993 | udf_info("UDF: Mounting volume '%s', " |
1862 | "timestamp %04u/%02u/%02u %02u:%02u (%x)\n", | 1994 | "timestamp %04u/%02u/%02u %02u:%02u (%x)\n", |
1863 | sbi->s_volume_ident, ts.year, ts.month, ts.day, | 1995 | sbi->s_volume_ident, le16_to_cpu(ts.year), ts.month, ts.day, |
1864 | ts.hour, ts.minute, ts.typeAndTimezone); | 1996 | ts.hour, ts.minute, le16_to_cpu(ts.typeAndTimezone)); |
1865 | } | 1997 | } |
1866 | if (!(sb->s_flags & MS_RDONLY)) | 1998 | if (!(sb->s_flags & MS_RDONLY)) |
1867 | udf_open_lvid(sb); | 1999 | udf_open_lvid(sb); |
@@ -1890,21 +2022,9 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) | |||
1890 | error_out: | 2022 | error_out: |
1891 | if (sbi->s_vat_inode) | 2023 | if (sbi->s_vat_inode) |
1892 | iput(sbi->s_vat_inode); | 2024 | iput(sbi->s_vat_inode); |
1893 | if (sbi->s_partitions) { | 2025 | if (sbi->s_partitions) |
1894 | struct udf_part_map *map = &sbi->s_partmaps[sbi->s_partition]; | 2026 | for (i = 0; i < sbi->s_partitions; i++) |
1895 | if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) | 2027 | udf_free_partition(&sbi->s_partmaps[i]); |
1896 | iput(map->s_uspace.s_table); | ||
1897 | if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) | ||
1898 | iput(map->s_fspace.s_table); | ||
1899 | if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) | ||
1900 | udf_sb_free_bitmap(map->s_uspace.s_bitmap); | ||
1901 | if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) | ||
1902 | udf_sb_free_bitmap(map->s_fspace.s_bitmap); | ||
1903 | if (map->s_partition_type == UDF_SPARABLE_MAP15) | ||
1904 | for (i = 0; i < 4; i++) | ||
1905 | brelse(map->s_type_specific.s_sparing. | ||
1906 | s_spar_map[i]); | ||
1907 | } | ||
1908 | #ifdef CONFIG_UDF_NLS | 2028 | #ifdef CONFIG_UDF_NLS |
1909 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) | 2029 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) |
1910 | unload_nls(sbi->s_nls_map); | 2030 | unload_nls(sbi->s_nls_map); |
@@ -1920,8 +2040,8 @@ error_out: | |||
1920 | return -EINVAL; | 2040 | return -EINVAL; |
1921 | } | 2041 | } |
1922 | 2042 | ||
1923 | void udf_error(struct super_block *sb, const char *function, | 2043 | static void udf_error(struct super_block *sb, const char *function, |
1924 | const char *fmt, ...) | 2044 | const char *fmt, ...) |
1925 | { | 2045 | { |
1926 | va_list args; | 2046 | va_list args; |
1927 | 2047 | ||
@@ -1948,19 +2068,6 @@ void udf_warning(struct super_block *sb, const char *function, | |||
1948 | sb->s_id, function, error_buf); | 2068 | sb->s_id, function, error_buf); |
1949 | } | 2069 | } |
1950 | 2070 | ||
1951 | /* | ||
1952 | * udf_put_super | ||
1953 | * | ||
1954 | * PURPOSE | ||
1955 | * Prepare for destruction of the superblock. | ||
1956 | * | ||
1957 | * DESCRIPTION | ||
1958 | * Called before the filesystem is unmounted. | ||
1959 | * | ||
1960 | * HISTORY | ||
1961 | * July 1, 1997 - Andrew E. Mileski | ||
1962 | * Written, tested, and released. | ||
1963 | */ | ||
1964 | static void udf_put_super(struct super_block *sb) | 2071 | static void udf_put_super(struct super_block *sb) |
1965 | { | 2072 | { |
1966 | int i; | 2073 | int i; |
@@ -1969,21 +2076,9 @@ static void udf_put_super(struct super_block *sb) | |||
1969 | sbi = UDF_SB(sb); | 2076 | sbi = UDF_SB(sb); |
1970 | if (sbi->s_vat_inode) | 2077 | if (sbi->s_vat_inode) |
1971 | iput(sbi->s_vat_inode); | 2078 | iput(sbi->s_vat_inode); |
1972 | if (sbi->s_partitions) { | 2079 | if (sbi->s_partitions) |
1973 | struct udf_part_map *map = &sbi->s_partmaps[sbi->s_partition]; | 2080 | for (i = 0; i < sbi->s_partitions; i++) |
1974 | if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) | 2081 | udf_free_partition(&sbi->s_partmaps[i]); |
1975 | iput(map->s_uspace.s_table); | ||
1976 | if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) | ||
1977 | iput(map->s_fspace.s_table); | ||
1978 | if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) | ||
1979 | udf_sb_free_bitmap(map->s_uspace.s_bitmap); | ||
1980 | if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) | ||
1981 | udf_sb_free_bitmap(map->s_fspace.s_bitmap); | ||
1982 | if (map->s_partition_type == UDF_SPARABLE_MAP15) | ||
1983 | for (i = 0; i < 4; i++) | ||
1984 | brelse(map->s_type_specific.s_sparing. | ||
1985 | s_spar_map[i]); | ||
1986 | } | ||
1987 | #ifdef CONFIG_UDF_NLS | 2082 | #ifdef CONFIG_UDF_NLS |
1988 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) | 2083 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) |
1989 | unload_nls(sbi->s_nls_map); | 2084 | unload_nls(sbi->s_nls_map); |
@@ -1996,19 +2091,6 @@ static void udf_put_super(struct super_block *sb) | |||
1996 | sb->s_fs_info = NULL; | 2091 | sb->s_fs_info = NULL; |
1997 | } | 2092 | } |
1998 | 2093 | ||
1999 | /* | ||
2000 | * udf_stat_fs | ||
2001 | * | ||
2002 | * PURPOSE | ||
2003 | * Return info about the filesystem. | ||
2004 | * | ||
2005 | * DESCRIPTION | ||
2006 | * Called by sys_statfs() | ||
2007 | * | ||
2008 | * HISTORY | ||
2009 | * July 1, 1997 - Andrew E. Mileski | ||
2010 | * Written, tested, and released. | ||
2011 | */ | ||
2012 | static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) | 2094 | static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) |
2013 | { | 2095 | { |
2014 | struct super_block *sb = dentry->d_sb; | 2096 | struct super_block *sb = dentry->d_sb; |
@@ -2035,10 +2117,6 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
2035 | return 0; | 2117 | return 0; |
2036 | } | 2118 | } |
2037 | 2119 | ||
2038 | static unsigned char udf_bitmap_lookup[16] = { | ||
2039 | 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 | ||
2040 | }; | ||
2041 | |||
2042 | static unsigned int udf_count_free_bitmap(struct super_block *sb, | 2120 | static unsigned int udf_count_free_bitmap(struct super_block *sb, |
2043 | struct udf_bitmap *bitmap) | 2121 | struct udf_bitmap *bitmap) |
2044 | { | 2122 | { |
@@ -2048,7 +2126,6 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, | |||
2048 | int block = 0, newblock; | 2126 | int block = 0, newblock; |
2049 | kernel_lb_addr loc; | 2127 | kernel_lb_addr loc; |
2050 | uint32_t bytes; | 2128 | uint32_t bytes; |
2051 | uint8_t value; | ||
2052 | uint8_t *ptr; | 2129 | uint8_t *ptr; |
2053 | uint16_t ident; | 2130 | uint16_t ident; |
2054 | struct spaceBitmapDesc *bm; | 2131 | struct spaceBitmapDesc *bm; |
@@ -2074,13 +2151,10 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, | |||
2074 | ptr = (uint8_t *)bh->b_data; | 2151 | ptr = (uint8_t *)bh->b_data; |
2075 | 2152 | ||
2076 | while (bytes > 0) { | 2153 | while (bytes > 0) { |
2077 | while ((bytes > 0) && (index < sb->s_blocksize)) { | 2154 | u32 cur_bytes = min_t(u32, bytes, sb->s_blocksize - index); |
2078 | value = ptr[index]; | 2155 | accum += bitmap_weight((const unsigned long *)(ptr + index), |
2079 | accum += udf_bitmap_lookup[value & 0x0f]; | 2156 | cur_bytes * 8); |
2080 | accum += udf_bitmap_lookup[value >> 4]; | 2157 | bytes -= cur_bytes; |
2081 | index++; | ||
2082 | bytes--; | ||
2083 | } | ||
2084 | if (bytes) { | 2158 | if (bytes) { |
2085 | brelse(bh); | 2159 | brelse(bh); |
2086 | newblock = udf_get_lb_pblock(sb, loc, ++block); | 2160 | newblock = udf_get_lb_pblock(sb, loc, ++block); |
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c index 6ec99221e50c..c3265e1385d4 100644 --- a/fs/udf/symlink.c +++ b/fs/udf/symlink.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
24 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
25 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
26 | #include <linux/udf_fs.h> | ||
27 | #include <linux/time.h> | 26 | #include <linux/time.h> |
28 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
29 | #include <linux/stat.h> | 28 | #include <linux/stat.h> |
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c index fe61be17cdab..65e19b4f9424 100644 --- a/fs/udf/truncate.c +++ b/fs/udf/truncate.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include "udfdecl.h" | 22 | #include "udfdecl.h" |
23 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
24 | #include <linux/mm.h> | 24 | #include <linux/mm.h> |
25 | #include <linux/udf_fs.h> | ||
26 | #include <linux/buffer_head.h> | 25 | #include <linux/buffer_head.h> |
27 | 26 | ||
28 | #include "udf_i.h" | 27 | #include "udf_i.h" |
@@ -180,6 +179,24 @@ void udf_discard_prealloc(struct inode *inode) | |||
180 | brelse(epos.bh); | 179 | brelse(epos.bh); |
181 | } | 180 | } |
182 | 181 | ||
182 | static void udf_update_alloc_ext_desc(struct inode *inode, | ||
183 | struct extent_position *epos, | ||
184 | u32 lenalloc) | ||
185 | { | ||
186 | struct super_block *sb = inode->i_sb; | ||
187 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
188 | |||
189 | struct allocExtDesc *aed = (struct allocExtDesc *) (epos->bh->b_data); | ||
190 | int len = sizeof(struct allocExtDesc); | ||
191 | |||
192 | aed->lengthAllocDescs = cpu_to_le32(lenalloc); | ||
193 | if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || sbi->s_udfrev >= 0x0201) | ||
194 | len += lenalloc; | ||
195 | |||
196 | udf_update_tag(epos->bh->b_data, len); | ||
197 | mark_buffer_dirty_inode(epos->bh, inode); | ||
198 | } | ||
199 | |||
183 | void udf_truncate_extents(struct inode *inode) | 200 | void udf_truncate_extents(struct inode *inode) |
184 | { | 201 | { |
185 | struct extent_position epos; | 202 | struct extent_position epos; |
@@ -187,7 +204,6 @@ void udf_truncate_extents(struct inode *inode) | |||
187 | uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc; | 204 | uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc; |
188 | int8_t etype; | 205 | int8_t etype; |
189 | struct super_block *sb = inode->i_sb; | 206 | struct super_block *sb = inode->i_sb; |
190 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
191 | sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset; | 207 | sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset; |
192 | loff_t byte_offset; | 208 | loff_t byte_offset; |
193 | int adsize; | 209 | int adsize; |
@@ -224,35 +240,15 @@ void udf_truncate_extents(struct inode *inode) | |||
224 | if (indirect_ext_len) { | 240 | if (indirect_ext_len) { |
225 | /* We managed to free all extents in the | 241 | /* We managed to free all extents in the |
226 | * indirect extent - free it too */ | 242 | * indirect extent - free it too */ |
227 | if (!epos.bh) | 243 | BUG_ON(!epos.bh); |
228 | BUG(); | ||
229 | udf_free_blocks(sb, inode, epos.block, | 244 | udf_free_blocks(sb, inode, epos.block, |
230 | 0, indirect_ext_len); | 245 | 0, indirect_ext_len); |
231 | } else { | 246 | } else if (!epos.bh) { |
232 | if (!epos.bh) { | 247 | iinfo->i_lenAlloc = lenalloc; |
233 | iinfo->i_lenAlloc = | 248 | mark_inode_dirty(inode); |
234 | lenalloc; | 249 | } else |
235 | mark_inode_dirty(inode); | 250 | udf_update_alloc_ext_desc(inode, |
236 | } else { | 251 | &epos, lenalloc); |
237 | struct allocExtDesc *aed = | ||
238 | (struct allocExtDesc *) | ||
239 | (epos.bh->b_data); | ||
240 | int len = | ||
241 | sizeof(struct allocExtDesc); | ||
242 | |||
243 | aed->lengthAllocDescs = | ||
244 | cpu_to_le32(lenalloc); | ||
245 | if (!UDF_QUERY_FLAG(sb, | ||
246 | UDF_FLAG_STRICT) || | ||
247 | sbi->s_udfrev >= 0x0201) | ||
248 | len += lenalloc; | ||
249 | |||
250 | udf_update_tag(epos.bh->b_data, | ||
251 | len); | ||
252 | mark_buffer_dirty_inode( | ||
253 | epos.bh, inode); | ||
254 | } | ||
255 | } | ||
256 | brelse(epos.bh); | 252 | brelse(epos.bh); |
257 | epos.offset = sizeof(struct allocExtDesc); | 253 | epos.offset = sizeof(struct allocExtDesc); |
258 | epos.block = eloc; | 254 | epos.block = eloc; |
@@ -272,29 +268,14 @@ void udf_truncate_extents(struct inode *inode) | |||
272 | } | 268 | } |
273 | 269 | ||
274 | if (indirect_ext_len) { | 270 | if (indirect_ext_len) { |
275 | if (!epos.bh) | 271 | BUG_ON(!epos.bh); |
276 | BUG(); | ||
277 | udf_free_blocks(sb, inode, epos.block, 0, | 272 | udf_free_blocks(sb, inode, epos.block, 0, |
278 | indirect_ext_len); | 273 | indirect_ext_len); |
279 | } else { | 274 | } else if (!epos.bh) { |
280 | if (!epos.bh) { | 275 | iinfo->i_lenAlloc = lenalloc; |
281 | iinfo->i_lenAlloc = lenalloc; | 276 | mark_inode_dirty(inode); |
282 | mark_inode_dirty(inode); | 277 | } else |
283 | } else { | 278 | udf_update_alloc_ext_desc(inode, &epos, lenalloc); |
284 | struct allocExtDesc *aed = | ||
285 | (struct allocExtDesc *)(epos.bh->b_data); | ||
286 | aed->lengthAllocDescs = cpu_to_le32(lenalloc); | ||
287 | if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || | ||
288 | sbi->s_udfrev >= 0x0201) | ||
289 | udf_update_tag(epos.bh->b_data, | ||
290 | lenalloc + | ||
291 | sizeof(struct allocExtDesc)); | ||
292 | else | ||
293 | udf_update_tag(epos.bh->b_data, | ||
294 | sizeof(struct allocExtDesc)); | ||
295 | mark_buffer_dirty_inode(epos.bh, inode); | ||
296 | } | ||
297 | } | ||
298 | } else if (inode->i_size) { | 279 | } else if (inode->i_size) { |
299 | if (byte_offset) { | 280 | if (byte_offset) { |
300 | kernel_long_ad extent; | 281 | kernel_long_ad extent; |
diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h index ccc52f16bf7d..4f86b1d98a5d 100644 --- a/fs/udf/udf_i.h +++ b/fs/udf/udf_i.h | |||
@@ -1,10 +1,32 @@ | |||
1 | #ifndef __LINUX_UDF_I_H | 1 | #ifndef _UDF_I_H |
2 | #define __LINUX_UDF_I_H | 2 | #define _UDF_I_H |
3 | |||
4 | struct udf_inode_info { | ||
5 | struct timespec i_crtime; | ||
6 | /* Physical address of inode */ | ||
7 | kernel_lb_addr i_location; | ||
8 | __u64 i_unique; | ||
9 | __u32 i_lenEAttr; | ||
10 | __u32 i_lenAlloc; | ||
11 | __u64 i_lenExtents; | ||
12 | __u32 i_next_alloc_block; | ||
13 | __u32 i_next_alloc_goal; | ||
14 | unsigned i_alloc_type : 3; | ||
15 | unsigned i_efe : 1; /* extendedFileEntry */ | ||
16 | unsigned i_use : 1; /* unallocSpaceEntry */ | ||
17 | unsigned i_strat4096 : 1; | ||
18 | unsigned reserved : 26; | ||
19 | union { | ||
20 | short_ad *i_sad; | ||
21 | long_ad *i_lad; | ||
22 | __u8 *i_data; | ||
23 | } i_ext; | ||
24 | struct inode vfs_inode; | ||
25 | }; | ||
3 | 26 | ||
4 | #include <linux/udf_fs_i.h> | ||
5 | static inline struct udf_inode_info *UDF_I(struct inode *inode) | 27 | static inline struct udf_inode_info *UDF_I(struct inode *inode) |
6 | { | 28 | { |
7 | return list_entry(inode, struct udf_inode_info, vfs_inode); | 29 | return list_entry(inode, struct udf_inode_info, vfs_inode); |
8 | } | 30 | } |
9 | 31 | ||
10 | #endif /* !defined(_LINUX_UDF_I_H) */ | 32 | #endif /* _UDF_I_H) */ |
diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index 737d1c604eea..1c1c514a9725 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h | |||
@@ -1,10 +1,12 @@ | |||
1 | #ifndef __LINUX_UDF_SB_H | 1 | #ifndef __LINUX_UDF_SB_H |
2 | #define __LINUX_UDF_SB_H | 2 | #define __LINUX_UDF_SB_H |
3 | 3 | ||
4 | #include <linux/mutex.h> | ||
5 | |||
4 | /* Since UDF 2.01 is ISO 13346 based... */ | 6 | /* Since UDF 2.01 is ISO 13346 based... */ |
5 | #define UDF_SUPER_MAGIC 0x15013346 | 7 | #define UDF_SUPER_MAGIC 0x15013346 |
6 | 8 | ||
7 | #define UDF_MAX_READ_VERSION 0x0201 | 9 | #define UDF_MAX_READ_VERSION 0x0250 |
8 | #define UDF_MAX_WRITE_VERSION 0x0201 | 10 | #define UDF_MAX_WRITE_VERSION 0x0201 |
9 | 11 | ||
10 | #define UDF_FLAG_USE_EXTENDED_FE 0 | 12 | #define UDF_FLAG_USE_EXTENDED_FE 0 |
@@ -38,6 +40,111 @@ | |||
38 | #define UDF_PART_FLAG_REWRITABLE 0x0040 | 40 | #define UDF_PART_FLAG_REWRITABLE 0x0040 |
39 | #define UDF_PART_FLAG_OVERWRITABLE 0x0080 | 41 | #define UDF_PART_FLAG_OVERWRITABLE 0x0080 |
40 | 42 | ||
43 | #define UDF_MAX_BLOCK_LOADED 8 | ||
44 | |||
45 | #define UDF_TYPE1_MAP15 0x1511U | ||
46 | #define UDF_VIRTUAL_MAP15 0x1512U | ||
47 | #define UDF_VIRTUAL_MAP20 0x2012U | ||
48 | #define UDF_SPARABLE_MAP15 0x1522U | ||
49 | #define UDF_METADATA_MAP25 0x2511U | ||
50 | |||
51 | #pragma pack(1) /* XXX(hch): Why? This file just defines in-core structures */ | ||
52 | |||
53 | struct udf_meta_data { | ||
54 | __u32 s_meta_file_loc; | ||
55 | __u32 s_mirror_file_loc; | ||
56 | __u32 s_bitmap_file_loc; | ||
57 | __u32 s_alloc_unit_size; | ||
58 | __u16 s_align_unit_size; | ||
59 | __u8 s_dup_md_flag; | ||
60 | struct inode *s_metadata_fe; | ||
61 | struct inode *s_mirror_fe; | ||
62 | struct inode *s_bitmap_fe; | ||
63 | }; | ||
64 | |||
65 | struct udf_sparing_data { | ||
66 | __u16 s_packet_len; | ||
67 | struct buffer_head *s_spar_map[4]; | ||
68 | }; | ||
69 | |||
70 | struct udf_virtual_data { | ||
71 | __u32 s_num_entries; | ||
72 | __u16 s_start_offset; | ||
73 | }; | ||
74 | |||
75 | struct udf_bitmap { | ||
76 | __u32 s_extLength; | ||
77 | __u32 s_extPosition; | ||
78 | __u16 s_nr_groups; | ||
79 | struct buffer_head **s_block_bitmap; | ||
80 | }; | ||
81 | |||
82 | struct udf_part_map { | ||
83 | union { | ||
84 | struct udf_bitmap *s_bitmap; | ||
85 | struct inode *s_table; | ||
86 | } s_uspace; | ||
87 | union { | ||
88 | struct udf_bitmap *s_bitmap; | ||
89 | struct inode *s_table; | ||
90 | } s_fspace; | ||
91 | __u32 s_partition_root; | ||
92 | __u32 s_partition_len; | ||
93 | __u16 s_partition_type; | ||
94 | __u16 s_partition_num; | ||
95 | union { | ||
96 | struct udf_sparing_data s_sparing; | ||
97 | struct udf_virtual_data s_virtual; | ||
98 | struct udf_meta_data s_metadata; | ||
99 | } s_type_specific; | ||
100 | __u32 (*s_partition_func)(struct super_block *, __u32, __u16, __u32); | ||
101 | __u16 s_volumeseqnum; | ||
102 | __u16 s_partition_flags; | ||
103 | }; | ||
104 | |||
105 | #pragma pack() | ||
106 | |||
107 | struct udf_sb_info { | ||
108 | struct udf_part_map *s_partmaps; | ||
109 | __u8 s_volume_ident[32]; | ||
110 | |||
111 | /* Overall info */ | ||
112 | __u16 s_partitions; | ||
113 | __u16 s_partition; | ||
114 | |||
115 | /* Sector headers */ | ||
116 | __s32 s_session; | ||
117 | __u32 s_anchor[3]; | ||
118 | __u32 s_last_block; | ||
119 | |||
120 | struct buffer_head *s_lvid_bh; | ||
121 | |||
122 | /* Default permissions */ | ||
123 | mode_t s_umask; | ||
124 | gid_t s_gid; | ||
125 | uid_t s_uid; | ||
126 | |||
127 | /* Root Info */ | ||
128 | struct timespec s_record_time; | ||
129 | |||
130 | /* Fileset Info */ | ||
131 | __u16 s_serial_number; | ||
132 | |||
133 | /* highest UDF revision we have recorded to this media */ | ||
134 | __u16 s_udfrev; | ||
135 | |||
136 | /* Miscellaneous flags */ | ||
137 | __u32 s_flags; | ||
138 | |||
139 | /* Encoding info */ | ||
140 | struct nls_table *s_nls_map; | ||
141 | |||
142 | /* VAT inode */ | ||
143 | struct inode *s_vat_inode; | ||
144 | |||
145 | struct mutex s_alloc_mutex; | ||
146 | }; | ||
147 | |||
41 | static inline struct udf_sb_info *UDF_SB(struct super_block *sb) | 148 | static inline struct udf_sb_info *UDF_SB(struct super_block *sb) |
42 | { | 149 | { |
43 | return sb->s_fs_info; | 150 | return sb->s_fs_info; |
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 681dc2b66cdb..f3f45d029277 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h | |||
@@ -1,17 +1,37 @@ | |||
1 | #ifndef __UDF_DECL_H | 1 | #ifndef __UDF_DECL_H |
2 | #define __UDF_DECL_H | 2 | #define __UDF_DECL_H |
3 | 3 | ||
4 | #include <linux/udf_fs.h> | ||
5 | #include "ecma_167.h" | 4 | #include "ecma_167.h" |
6 | #include "osta_udf.h" | 5 | #include "osta_udf.h" |
7 | 6 | ||
8 | #include <linux/fs.h> | 7 | #include <linux/fs.h> |
9 | #include <linux/types.h> | 8 | #include <linux/types.h> |
10 | #include <linux/udf_fs_i.h> | ||
11 | #include <linux/udf_fs_sb.h> | ||
12 | #include <linux/buffer_head.h> | 9 | #include <linux/buffer_head.h> |
10 | #include <linux/udf_fs_i.h> | ||
13 | 11 | ||
12 | #include "udf_sb.h" | ||
14 | #include "udfend.h" | 13 | #include "udfend.h" |
14 | #include "udf_i.h" | ||
15 | |||
16 | #define UDF_PREALLOCATE | ||
17 | #define UDF_DEFAULT_PREALLOC_BLOCKS 8 | ||
18 | |||
19 | #define UDFFS_DEBUG | ||
20 | |||
21 | #ifdef UDFFS_DEBUG | ||
22 | #define udf_debug(f, a...) \ | ||
23 | do { \ | ||
24 | printk(KERN_DEBUG "UDF-fs DEBUG %s:%d:%s: ", \ | ||
25 | __FILE__, __LINE__, __func__); \ | ||
26 | printk(f, ##a); \ | ||
27 | } while (0) | ||
28 | #else | ||
29 | #define udf_debug(f, a...) /**/ | ||
30 | #endif | ||
31 | |||
32 | #define udf_info(f, a...) \ | ||
33 | printk(KERN_INFO "UDF-fs INFO " f, ##a); | ||
34 | |||
15 | 35 | ||
16 | #define udf_fixed_to_variable(x) ( ( ( (x) >> 5 ) * 39 ) + ( (x) & 0x0000001F ) ) | 36 | #define udf_fixed_to_variable(x) ( ( ( (x) >> 5 ) * 39 ) + ( (x) & 0x0000001F ) ) |
17 | #define udf_variable_to_fixed(x) ( ( ( (x) / 39 ) << 5 ) + ( (x) % 39 ) ) | 37 | #define udf_variable_to_fixed(x) ( ( ( (x) / 39 ) << 5 ) + ( (x) % 39 ) ) |
@@ -23,16 +43,24 @@ | |||
23 | #define UDF_NAME_LEN 256 | 43 | #define UDF_NAME_LEN 256 |
24 | #define UDF_PATH_LEN 1023 | 44 | #define UDF_PATH_LEN 1023 |
25 | 45 | ||
26 | #define udf_file_entry_alloc_offset(inode)\ | 46 | static inline size_t udf_file_entry_alloc_offset(struct inode *inode) |
27 | (UDF_I(inode)->i_use ?\ | 47 | { |
28 | sizeof(struct unallocSpaceEntry) :\ | 48 | struct udf_inode_info *iinfo = UDF_I(inode); |
29 | ((UDF_I(inode)->i_efe ?\ | 49 | if (iinfo->i_use) |
30 | sizeof(struct extendedFileEntry) :\ | 50 | return sizeof(struct unallocSpaceEntry); |
31 | sizeof(struct fileEntry)) + UDF_I(inode)->i_lenEAttr)) | 51 | else if (iinfo->i_efe) |
32 | 52 | return sizeof(struct extendedFileEntry) + iinfo->i_lenEAttr; | |
33 | #define udf_ext0_offset(inode)\ | 53 | else |
34 | (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ?\ | 54 | return sizeof(struct fileEntry) + iinfo->i_lenEAttr; |
35 | udf_file_entry_alloc_offset(inode) : 0) | 55 | } |
56 | |||
57 | static inline size_t udf_ext0_offset(struct inode *inode) | ||
58 | { | ||
59 | if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) | ||
60 | return udf_file_entry_alloc_offset(inode); | ||
61 | else | ||
62 | return 0; | ||
63 | } | ||
36 | 64 | ||
37 | #define udf_get_lb_pblock(sb,loc,offset) udf_get_pblock((sb), (loc).logicalBlockNum, (loc).partitionReferenceNum, (offset)) | 65 | #define udf_get_lb_pblock(sb,loc,offset) udf_get_pblock((sb), (loc).logicalBlockNum, (loc).partitionReferenceNum, (offset)) |
38 | 66 | ||
@@ -83,7 +111,6 @@ struct extent_position { | |||
83 | }; | 111 | }; |
84 | 112 | ||
85 | /* super.c */ | 113 | /* super.c */ |
86 | extern void udf_error(struct super_block *, const char *, const char *, ...); | ||
87 | extern void udf_warning(struct super_block *, const char *, const char *, ...); | 114 | extern void udf_warning(struct super_block *, const char *, const char *, ...); |
88 | 115 | ||
89 | /* namei.c */ | 116 | /* namei.c */ |
@@ -150,6 +177,8 @@ extern uint32_t udf_get_pblock_virt20(struct super_block *, uint32_t, uint16_t, | |||
150 | uint32_t); | 177 | uint32_t); |
151 | extern uint32_t udf_get_pblock_spar15(struct super_block *, uint32_t, uint16_t, | 178 | extern uint32_t udf_get_pblock_spar15(struct super_block *, uint32_t, uint16_t, |
152 | uint32_t); | 179 | uint32_t); |
180 | extern uint32_t udf_get_pblock_meta25(struct super_block *, uint32_t, uint16_t, | ||
181 | uint32_t); | ||
153 | extern int udf_relocate_blocks(struct super_block *, long, long *); | 182 | extern int udf_relocate_blocks(struct super_block *, long, long *); |
154 | 183 | ||
155 | /* unicode.c */ | 184 | /* unicode.c */ |
@@ -157,7 +186,7 @@ extern int udf_get_filename(struct super_block *, uint8_t *, uint8_t *, int); | |||
157 | extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *, | 186 | extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *, |
158 | int); | 187 | int); |
159 | extern int udf_build_ustr(struct ustr *, dstring *, int); | 188 | extern int udf_build_ustr(struct ustr *, dstring *, int); |
160 | extern int udf_CS0toUTF8(struct ustr *, struct ustr *); | 189 | extern int udf_CS0toUTF8(struct ustr *, const struct ustr *); |
161 | 190 | ||
162 | /* ialloc.c */ | 191 | /* ialloc.c */ |
163 | extern void udf_free_inode(struct inode *); | 192 | extern void udf_free_inode(struct inode *); |
@@ -191,11 +220,9 @@ extern struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, | |||
191 | extern long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int); | 220 | extern long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int); |
192 | extern short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int); | 221 | extern short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int); |
193 | 222 | ||
194 | /* crc.c */ | ||
195 | extern uint16_t udf_crc(uint8_t *, uint32_t, uint16_t); | ||
196 | |||
197 | /* udftime.c */ | 223 | /* udftime.c */ |
198 | extern time_t *udf_stamp_to_time(time_t *, long *, kernel_timestamp); | 224 | extern struct timespec *udf_disk_stamp_to_time(struct timespec *dest, |
199 | extern kernel_timestamp *udf_time_to_stamp(kernel_timestamp *, struct timespec); | 225 | timestamp src); |
226 | extern timestamp *udf_time_to_disk_stamp(timestamp *dest, struct timespec src); | ||
200 | 227 | ||
201 | #endif /* __UDF_DECL_H */ | 228 | #endif /* __UDF_DECL_H */ |
diff --git a/fs/udf/udfend.h b/fs/udf/udfend.h index c4bd1203f857..489f52fb428c 100644 --- a/fs/udf/udfend.h +++ b/fs/udf/udfend.h | |||
@@ -24,17 +24,6 @@ static inline lb_addr cpu_to_lelb(kernel_lb_addr in) | |||
24 | return out; | 24 | return out; |
25 | } | 25 | } |
26 | 26 | ||
27 | static inline kernel_timestamp lets_to_cpu(timestamp in) | ||
28 | { | ||
29 | kernel_timestamp out; | ||
30 | |||
31 | memcpy(&out, &in, sizeof(timestamp)); | ||
32 | out.typeAndTimezone = le16_to_cpu(in.typeAndTimezone); | ||
33 | out.year = le16_to_cpu(in.year); | ||
34 | |||
35 | return out; | ||
36 | } | ||
37 | |||
38 | static inline short_ad lesa_to_cpu(short_ad in) | 27 | static inline short_ad lesa_to_cpu(short_ad in) |
39 | { | 28 | { |
40 | short_ad out; | 29 | short_ad out; |
@@ -85,15 +74,4 @@ static inline kernel_extent_ad leea_to_cpu(extent_ad in) | |||
85 | return out; | 74 | return out; |
86 | } | 75 | } |
87 | 76 | ||
88 | static inline timestamp cpu_to_lets(kernel_timestamp in) | ||
89 | { | ||
90 | timestamp out; | ||
91 | |||
92 | memcpy(&out, &in, sizeof(timestamp)); | ||
93 | out.typeAndTimezone = cpu_to_le16(in.typeAndTimezone); | ||
94 | out.year = cpu_to_le16(in.year); | ||
95 | |||
96 | return out; | ||
97 | } | ||
98 | |||
99 | #endif /* __UDF_ENDIAN_H */ | 77 | #endif /* __UDF_ENDIAN_H */ |
diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c index ce595732ba6f..5f811655c9b5 100644 --- a/fs/udf/udftime.c +++ b/fs/udf/udftime.c | |||
@@ -85,39 +85,38 @@ extern struct timezone sys_tz; | |||
85 | #define SECS_PER_HOUR (60 * 60) | 85 | #define SECS_PER_HOUR (60 * 60) |
86 | #define SECS_PER_DAY (SECS_PER_HOUR * 24) | 86 | #define SECS_PER_DAY (SECS_PER_HOUR * 24) |
87 | 87 | ||
88 | time_t *udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src) | 88 | struct timespec *udf_disk_stamp_to_time(struct timespec *dest, timestamp src) |
89 | { | 89 | { |
90 | int yday; | 90 | int yday; |
91 | uint8_t type = src.typeAndTimezone >> 12; | 91 | u16 typeAndTimezone = le16_to_cpu(src.typeAndTimezone); |
92 | u16 year = le16_to_cpu(src.year); | ||
93 | uint8_t type = typeAndTimezone >> 12; | ||
92 | int16_t offset; | 94 | int16_t offset; |
93 | 95 | ||
94 | if (type == 1) { | 96 | if (type == 1) { |
95 | offset = src.typeAndTimezone << 4; | 97 | offset = typeAndTimezone << 4; |
96 | /* sign extent offset */ | 98 | /* sign extent offset */ |
97 | offset = (offset >> 4); | 99 | offset = (offset >> 4); |
98 | if (offset == -2047) /* unspecified offset */ | 100 | if (offset == -2047) /* unspecified offset */ |
99 | offset = 0; | 101 | offset = 0; |
100 | } else { | 102 | } else |
101 | offset = 0; | 103 | offset = 0; |
102 | } | ||
103 | 104 | ||
104 | if ((src.year < EPOCH_YEAR) || | 105 | if ((year < EPOCH_YEAR) || |
105 | (src.year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) { | 106 | (year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) { |
106 | *dest = -1; | ||
107 | *dest_usec = -1; | ||
108 | return NULL; | 107 | return NULL; |
109 | } | 108 | } |
110 | *dest = year_seconds[src.year - EPOCH_YEAR]; | 109 | dest->tv_sec = year_seconds[year - EPOCH_YEAR]; |
111 | *dest -= offset * 60; | 110 | dest->tv_sec -= offset * 60; |
112 | 111 | ||
113 | yday = ((__mon_yday[__isleap(src.year)][src.month - 1]) + src.day - 1); | 112 | yday = ((__mon_yday[__isleap(year)][src.month - 1]) + src.day - 1); |
114 | *dest += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second; | 113 | dest->tv_sec += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second; |
115 | *dest_usec = src.centiseconds * 10000 + | 114 | dest->tv_nsec = 1000 * (src.centiseconds * 10000 + |
116 | src.hundredsOfMicroseconds * 100 + src.microseconds; | 115 | src.hundredsOfMicroseconds * 100 + src.microseconds); |
117 | return dest; | 116 | return dest; |
118 | } | 117 | } |
119 | 118 | ||
120 | kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts) | 119 | timestamp *udf_time_to_disk_stamp(timestamp *dest, struct timespec ts) |
121 | { | 120 | { |
122 | long int days, rem, y; | 121 | long int days, rem, y; |
123 | const unsigned short int *ip; | 122 | const unsigned short int *ip; |
@@ -128,7 +127,7 @@ kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts) | |||
128 | if (!dest) | 127 | if (!dest) |
129 | return NULL; | 128 | return NULL; |
130 | 129 | ||
131 | dest->typeAndTimezone = 0x1000 | (offset & 0x0FFF); | 130 | dest->typeAndTimezone = cpu_to_le16(0x1000 | (offset & 0x0FFF)); |
132 | 131 | ||
133 | ts.tv_sec += offset * 60; | 132 | ts.tv_sec += offset * 60; |
134 | days = ts.tv_sec / SECS_PER_DAY; | 133 | days = ts.tv_sec / SECS_PER_DAY; |
@@ -151,7 +150,7 @@ kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts) | |||
151 | - LEAPS_THRU_END_OF(y - 1)); | 150 | - LEAPS_THRU_END_OF(y - 1)); |
152 | y = yg; | 151 | y = yg; |
153 | } | 152 | } |
154 | dest->year = y; | 153 | dest->year = cpu_to_le16(y); |
155 | ip = __mon_yday[__isleap(y)]; | 154 | ip = __mon_yday[__isleap(y)]; |
156 | for (y = 11; days < (long int)ip[y]; --y) | 155 | for (y = 11; days < (long int)ip[y]; --y) |
157 | continue; | 156 | continue; |
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index e533b11703bf..9fdf8c93c58e 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/string.h> /* for memset */ | 24 | #include <linux/string.h> /* for memset */ |
25 | #include <linux/nls.h> | 25 | #include <linux/nls.h> |
26 | #include <linux/udf_fs.h> | 26 | #include <linux/crc-itu-t.h> |
27 | 27 | ||
28 | #include "udf_sb.h" | 28 | #include "udf_sb.h" |
29 | 29 | ||
@@ -49,14 +49,16 @@ int udf_build_ustr(struct ustr *dest, dstring *ptr, int size) | |||
49 | { | 49 | { |
50 | int usesize; | 50 | int usesize; |
51 | 51 | ||
52 | if ((!dest) || (!ptr) || (!size)) | 52 | if (!dest || !ptr || !size) |
53 | return -1; | 53 | return -1; |
54 | BUG_ON(size < 2); | ||
54 | 55 | ||
55 | memset(dest, 0, sizeof(struct ustr)); | 56 | usesize = min_t(size_t, ptr[size - 1], sizeof(dest->u_name)); |
56 | usesize = (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size; | 57 | usesize = min(usesize, size - 2); |
57 | dest->u_cmpID = ptr[0]; | 58 | dest->u_cmpID = ptr[0]; |
58 | dest->u_len = ptr[size - 1]; | 59 | dest->u_len = usesize; |
59 | memcpy(dest->u_name, ptr + 1, usesize - 1); | 60 | memcpy(dest->u_name, ptr + 1, usesize); |
61 | memset(dest->u_name + usesize, 0, sizeof(dest->u_name) - usesize); | ||
60 | 62 | ||
61 | return 0; | 63 | return 0; |
62 | } | 64 | } |
@@ -83,9 +85,6 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) | |||
83 | * PURPOSE | 85 | * PURPOSE |
84 | * Convert OSTA Compressed Unicode to the UTF-8 equivalent. | 86 | * Convert OSTA Compressed Unicode to the UTF-8 equivalent. |
85 | * | 87 | * |
86 | * DESCRIPTION | ||
87 | * This routine is only called by udf_filldir(). | ||
88 | * | ||
89 | * PRE-CONDITIONS | 88 | * PRE-CONDITIONS |
90 | * utf Pointer to UTF-8 output buffer. | 89 | * utf Pointer to UTF-8 output buffer. |
91 | * ocu Pointer to OSTA Compressed Unicode input buffer | 90 | * ocu Pointer to OSTA Compressed Unicode input buffer |
@@ -99,43 +98,39 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) | |||
99 | * November 12, 1997 - Andrew E. Mileski | 98 | * November 12, 1997 - Andrew E. Mileski |
100 | * Written, tested, and released. | 99 | * Written, tested, and released. |
101 | */ | 100 | */ |
102 | int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i) | 101 | int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) |
103 | { | 102 | { |
104 | uint8_t *ocu; | 103 | const uint8_t *ocu; |
105 | uint32_t c; | ||
106 | uint8_t cmp_id, ocu_len; | 104 | uint8_t cmp_id, ocu_len; |
107 | int i; | 105 | int i; |
108 | 106 | ||
109 | ocu = ocu_i->u_name; | ||
110 | |||
111 | ocu_len = ocu_i->u_len; | 107 | ocu_len = ocu_i->u_len; |
112 | cmp_id = ocu_i->u_cmpID; | ||
113 | utf_o->u_len = 0; | ||
114 | |||
115 | if (ocu_len == 0) { | 108 | if (ocu_len == 0) { |
116 | memset(utf_o, 0, sizeof(struct ustr)); | 109 | memset(utf_o, 0, sizeof(struct ustr)); |
117 | utf_o->u_cmpID = 0; | ||
118 | utf_o->u_len = 0; | ||
119 | return 0; | 110 | return 0; |
120 | } | 111 | } |
121 | 112 | ||
122 | if ((cmp_id != 8) && (cmp_id != 16)) { | 113 | cmp_id = ocu_i->u_cmpID; |
114 | if (cmp_id != 8 && cmp_id != 16) { | ||
115 | memset(utf_o, 0, sizeof(struct ustr)); | ||
123 | printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", | 116 | printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", |
124 | cmp_id, ocu_i->u_name); | 117 | cmp_id, ocu_i->u_name); |
125 | return 0; | 118 | return 0; |
126 | } | 119 | } |
127 | 120 | ||
121 | ocu = ocu_i->u_name; | ||
122 | utf_o->u_len = 0; | ||
128 | for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) { | 123 | for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) { |
129 | 124 | ||
130 | /* Expand OSTA compressed Unicode to Unicode */ | 125 | /* Expand OSTA compressed Unicode to Unicode */ |
131 | c = ocu[i++]; | 126 | uint32_t c = ocu[i++]; |
132 | if (cmp_id == 16) | 127 | if (cmp_id == 16) |
133 | c = (c << 8) | ocu[i++]; | 128 | c = (c << 8) | ocu[i++]; |
134 | 129 | ||
135 | /* Compress Unicode to UTF-8 */ | 130 | /* Compress Unicode to UTF-8 */ |
136 | if (c < 0x80U) { | 131 | if (c < 0x80U) |
137 | utf_o->u_name[utf_o->u_len++] = (uint8_t)c; | 132 | utf_o->u_name[utf_o->u_len++] = (uint8_t)c; |
138 | } else if (c < 0x800U) { | 133 | else if (c < 0x800U) { |
139 | utf_o->u_name[utf_o->u_len++] = | 134 | utf_o->u_name[utf_o->u_len++] = |
140 | (uint8_t)(0xc0 | (c >> 6)); | 135 | (uint8_t)(0xc0 | (c >> 6)); |
141 | utf_o->u_name[utf_o->u_len++] = | 136 | utf_o->u_name[utf_o->u_len++] = |
@@ -255,35 +250,32 @@ error_out: | |||
255 | } | 250 | } |
256 | 251 | ||
257 | static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, | 252 | static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, |
258 | struct ustr *ocu_i) | 253 | const struct ustr *ocu_i) |
259 | { | 254 | { |
260 | uint8_t *ocu; | 255 | const uint8_t *ocu; |
261 | uint32_t c; | ||
262 | uint8_t cmp_id, ocu_len; | 256 | uint8_t cmp_id, ocu_len; |
263 | int i; | 257 | int i; |
264 | 258 | ||
265 | ocu = ocu_i->u_name; | ||
266 | 259 | ||
267 | ocu_len = ocu_i->u_len; | 260 | ocu_len = ocu_i->u_len; |
268 | cmp_id = ocu_i->u_cmpID; | ||
269 | utf_o->u_len = 0; | ||
270 | |||
271 | if (ocu_len == 0) { | 261 | if (ocu_len == 0) { |
272 | memset(utf_o, 0, sizeof(struct ustr)); | 262 | memset(utf_o, 0, sizeof(struct ustr)); |
273 | utf_o->u_cmpID = 0; | ||
274 | utf_o->u_len = 0; | ||
275 | return 0; | 263 | return 0; |
276 | } | 264 | } |
277 | 265 | ||
278 | if ((cmp_id != 8) && (cmp_id != 16)) { | 266 | cmp_id = ocu_i->u_cmpID; |
267 | if (cmp_id != 8 && cmp_id != 16) { | ||
268 | memset(utf_o, 0, sizeof(struct ustr)); | ||
279 | printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", | 269 | printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", |
280 | cmp_id, ocu_i->u_name); | 270 | cmp_id, ocu_i->u_name); |
281 | return 0; | 271 | return 0; |
282 | } | 272 | } |
283 | 273 | ||
274 | ocu = ocu_i->u_name; | ||
275 | utf_o->u_len = 0; | ||
284 | for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) { | 276 | for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) { |
285 | /* Expand OSTA compressed Unicode to Unicode */ | 277 | /* Expand OSTA compressed Unicode to Unicode */ |
286 | c = ocu[i++]; | 278 | uint32_t c = ocu[i++]; |
287 | if (cmp_id == 16) | 279 | if (cmp_id == 16) |
288 | c = (c << 8) | ocu[i++]; | 280 | c = (c << 8) | ocu[i++]; |
289 | 281 | ||
@@ -463,7 +455,7 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, | |||
463 | } else if (newIndex > 250) | 455 | } else if (newIndex > 250) |
464 | newIndex = 250; | 456 | newIndex = 250; |
465 | newName[newIndex++] = CRC_MARK; | 457 | newName[newIndex++] = CRC_MARK; |
466 | valueCRC = udf_crc(fidName, fidNameLen, 0); | 458 | valueCRC = crc_itu_t(0, fidName, fidNameLen); |
467 | newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12]; | 459 | newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12]; |
468 | newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8]; | 460 | newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8]; |
469 | newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4]; | 461 | newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4]; |
diff --git a/fs/xattr.c b/fs/xattr.c index f7062da505d4..89a942f07e1b 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
@@ -307,7 +307,6 @@ sys_fsetxattr(int fd, char __user *name, void __user *value, | |||
307 | error = setxattr(dentry, name, value, size, flags); | 307 | error = setxattr(dentry, name, value, size, flags); |
308 | mnt_drop_write(f->f_path.mnt); | 308 | mnt_drop_write(f->f_path.mnt); |
309 | } | 309 | } |
310 | out_fput: | ||
311 | fput(f); | 310 | fput(f); |
312 | return error; | 311 | return error; |
313 | } | 312 | } |